xref: /csrg-svn/usr.bin/finger/finger.c (revision 1014)
1*1014Sbill static char *sccsid = "@(#)finger.c	4.1 (Berkeley) 10/01/80";
2*1014Sbill 
3*1014Sbill /*  This is a finger program.  It prints out useful information about users
4*1014Sbill  *  by digging it up from various system files.  It is not very portable
5*1014Sbill  *  because the most useful parts of the information (the full user name,
6*1014Sbill  *  office, and phone numbers) are all stored in the VAX-unused gecos field
7*1014Sbill  *  of /etc/passwd, which, unfortunately, other UNIXes use for other things.
8*1014Sbill  *
9*1014Sbill  *  There are three output formats, all of which give login name, teletype
10*1014Sbill  *  line number, and login time.  The short output format is reminiscent
11*1014Sbill  *  of finger on ITS, and gives one line of information per user containing
12*1014Sbill  *  in addition to the minimum basic requirements (MBR), the full name of
13*1014Sbill  *  the user, his idle time and office location and phone number.  The
14*1014Sbill  *  quick style output is UNIX who-like, giving only name, teletype and
15*1014Sbill  *  login time.  Finally, the long style output give the same information
16*1014Sbill  *  as the short (in more legible format), the home directory and shell
17*1014Sbill  *  of the user, and, if it exits, a copy of the file .plan in the users
18*1014Sbill  *  home directory.  Finger may be called with or without a list of people
19*1014Sbill  *  to finger -- if no list is given, all the people currently logged in
20*1014Sbill  *  are fingered.
21*1014Sbill  *
22*1014Sbill  *  The program is validly called by one of the following:
23*1014Sbill  *
24*1014Sbill  *	finger			{short form list of users}
25*1014Sbill  *	finger -l		{long form list of users}
26*1014Sbill  *	finger -b		{briefer long form list of users}
27*1014Sbill  *	finger -q		{quick list of users}
28*1014Sbill  *	finger -i		{quick list of users with idle times}
29*1014Sbill  *	finger namelist		{long format list of specified users}
30*1014Sbill  *	finger -s namelist	{short format list of specified users}
31*1014Sbill  *	finger -w namelist	{narrow short format list of specified users}
32*1014Sbill  *
33*1014Sbill  *  where 'namelist' is a list of users login names.
34*1014Sbill  *  The other options can all be given after one '-', or each can have its
35*1014Sbill  *  own '-'.  The -f option disables the printing of headers for short and
36*1014Sbill  *  quick outputs.  The -b option briefens long format outputs.  The -p
37*1014Sbill  *  option turns off plans for long format outputs.
38*1014Sbill  */
39*1014Sbill 
40*1014Sbill #include	<sys/types.h>
41*1014Sbill #include	<sys/stat.h>
42*1014Sbill #include	<sgtty.h>
43*1014Sbill #include	<utmp.h>
44*1014Sbill #include	<signal.h>
45*1014Sbill #include	<pwd.h>
46*1014Sbill #include	<stdio.h>
47*1014Sbill #include	<sccs.h>
48*1014Sbill #include	<lastlog.h>
49*1014Sbill #include	<time.h>
50*1014Sbill 
51*1014Sbill struct	utmp	utmp;	/* for sizeof */
52*1014Sbill #define NMAX sizeof(utmp.ut_name)
53*1014Sbill #define LMAX sizeof(utmp.ut_line)
54*1014Sbill 
55*1014Sbill #define		ASTERISK	'*'	/* ignore this in real name */
56*1014Sbill #define		BLANK		' '	/* blank character (i.e. space) */
57*1014Sbill #define		CAPITALIZE	0137&	/* capitalize character macro */
58*1014Sbill #define		COMMA		','	/* separator in pw_gecos field */
59*1014Sbill #define		COMMAND		'-'	/* command line flag char */
60*1014Sbill #define		CORY		'C'	/* cory hall office */
61*1014Sbill #define		EVANS		'E'	/* evans hall office */
62*1014Sbill #define		LINEBREAK	012	/* line feed */
63*1014Sbill #define		NULLSTR		""	/* the null string, opposed to NULL */
64*1014Sbill #define		SAMENAME	'&'	/* repeat login name in real name */
65*1014Sbill #define		TALKABLE	0222	/* tty is writeable if 222 mode */
66*1014Sbill 
67*1014Sbill struct  person  {			/* one for each person fingered */
68*1014Sbill 	char		name[NMAX+1];	/* login name */
69*1014Sbill 	char		tty[LMAX+1];	/* NULL terminated tty line */
70*1014Sbill 	long		loginat;	/* time of login (possibly last) */
71*1014Sbill 	long		idletime;	/* how long idle (if logged in) */
72*1014Sbill 	short int	loggedin;	/* flag for being logged in */
73*1014Sbill 	short int	writeable;	/* flag for tty being writeable */
74*1014Sbill 	char		*realname;	/* pointer to full name */
75*1014Sbill 	char		*office;	/* pointer to office name */
76*1014Sbill 	char		*officephone;	/* pointer to office phone no. */
77*1014Sbill 	char		*homephone;	/* pointer to home phone no. */
78*1014Sbill 	char		*random;	/* for any random stuff in pw_gecos */
79*1014Sbill 	struct  passwd	*pwd;		/* structure of /etc/passwd stuff */
80*1014Sbill 	struct  person	*link;		/* link to next person */
81*1014Sbill };
82*1014Sbill 
83*1014Sbill struct  passwd			*NILPWD = 0;
84*1014Sbill struct  person			*NILPERS = 0;
85*1014Sbill 
86*1014Sbill int		persize		= sizeof( struct person );
87*1014Sbill int		pwdsize		= sizeof( struct passwd );
88*1014Sbill 
89*1014Sbill char		LASTLOG[]	= "/usr/adm/lastlog";	/* last login info */
90*1014Sbill char		USERLOG[]	= "/etc/utmp";		/* who is logged in */
91*1014Sbill char		outbuf[BUFSIZ];				/* output buffer */
92*1014Sbill char		*ctime();
93*1014Sbill 
94*1014Sbill int		unbrief		= 1;		/* -b option default */
95*1014Sbill int		header		= 1;		/* -f option default */
96*1014Sbill int		hack		= 1;		/* -h option default */
97*1014Sbill int		idle		= 0;		/* -i option default */
98*1014Sbill int		large		= 0;		/* -l option default */
99*1014Sbill int		match		= 1;		/* -m option default */
100*1014Sbill int		plan		= 1;		/* -p option default */
101*1014Sbill int		unquick		= 1;		/* -q option default */
102*1014Sbill int		small		= 0;		/* -s option default */
103*1014Sbill int		wide		= 1;		/* -w option default */
104*1014Sbill 
105*1014Sbill int		lf;
106*1014Sbill int		llopenerr;
107*1014Sbill 
108*1014Sbill long		tloc;				/* current time */
109*1014Sbill 
110*1014Sbill 
111*1014Sbill 
112*1014Sbill main( argc, argv )
113*1014Sbill 
114*1014Sbill     int		argc;
115*1014Sbill     char	*argv[];
116*1014Sbill 
117*1014Sbill {
118*1014Sbill 	FILE			*fp,  *fopen();		/* for plans */
119*1014Sbill 	struct  passwd		*getpwent();		/* read /etc/passwd */
120*1014Sbill 	struct  person		*person1,  *p,  *pend;	/* people */
121*1014Sbill 	struct  passwd		*pw;			/* temporary */
122*1014Sbill 	struct  utmp		user;			/*   ditto   */
123*1014Sbill 	char			*malloc();
124*1014Sbill 	char			*s,  *pn,  *ln;
125*1014Sbill 	char			c;
126*1014Sbill 	char			*PLAN = "/.plan";	/* what plan file is */
127*1014Sbill 	char			*PROJ = "/.project";	/* what project file */
128*1014Sbill 	int			PLANLEN = strlen( PLAN );
129*1014Sbill 	int			PROJLEN = strlen( PROJ );
130*1014Sbill 	int			numnames = 0;
131*1014Sbill 	int			orgnumnames;
132*1014Sbill 	int			uf;
133*1014Sbill 	int			usize = sizeof user;
134*1014Sbill 	int			unshort;
135*1014Sbill 	int			i, j;
136*1014Sbill 	int			fngrlogin;
137*1014Sbill 
138*1014Sbill 	setbuf( stdout, outbuf );			/* buffer output */
139*1014Sbill 
140*1014Sbill     /*  parse command line for (optional) arguments */
141*1014Sbill 
142*1014Sbill 	i = 1;
143*1014Sbill 	if(  strcmp( *argv, "sh" )  )  {
144*1014Sbill 	    fngrlogin = 0;
145*1014Sbill 	    while( i++ < argc  &&  (*++argv)[0] == COMMAND )  {
146*1014Sbill 		for( s = argv[0] + 1; *s != NULL; s++ )  {
147*1014Sbill 			switch  (*s)  {
148*1014Sbill 
149*1014Sbill 			    case 'b':
150*1014Sbill 				    unbrief = 0;
151*1014Sbill 				    break;
152*1014Sbill 
153*1014Sbill 			    case 'f':
154*1014Sbill 				    header = 0;
155*1014Sbill 				    break;
156*1014Sbill 
157*1014Sbill 			    case 'h':
158*1014Sbill 				    hack = 0;
159*1014Sbill 				    break;
160*1014Sbill 
161*1014Sbill 			    case 'i':
162*1014Sbill 				    idle = 1;
163*1014Sbill 				    unquick = 0;
164*1014Sbill 				    break;
165*1014Sbill 
166*1014Sbill 			    case 'l':
167*1014Sbill 				    large = 1;
168*1014Sbill 				    break;
169*1014Sbill 
170*1014Sbill 			    case 'm':
171*1014Sbill 				    match = 0;
172*1014Sbill 				    break;
173*1014Sbill 
174*1014Sbill 			    case 'p':
175*1014Sbill 				    plan = 0;
176*1014Sbill 				    break;
177*1014Sbill 
178*1014Sbill 			    case 'q':
179*1014Sbill 				    unquick = 0;
180*1014Sbill 				    break;
181*1014Sbill 
182*1014Sbill 			    case 's':
183*1014Sbill 				    small = 1;
184*1014Sbill 				    break;
185*1014Sbill 
186*1014Sbill 			    case 'w':
187*1014Sbill 				    wide = 0;
188*1014Sbill 				    break;
189*1014Sbill 
190*1014Sbill 			    default:
191*1014Sbill 				fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" );
192*1014Sbill 				exit( 1 );
193*1014Sbill 			}
194*1014Sbill 		}
195*1014Sbill 	    }
196*1014Sbill 	}
197*1014Sbill 	else  {
198*1014Sbill 	    fngrlogin = 1;
199*1014Sbill 	}
200*1014Sbill 	if( unquick )  {
201*1014Sbill 	    time( &tloc );
202*1014Sbill 	}
203*1014Sbill 	else  {
204*1014Sbill 	    if( idle )  {
205*1014Sbill 		time( &tloc );
206*1014Sbill 	    }
207*1014Sbill 	}
208*1014Sbill 
209*1014Sbill     /*  i > argc means no login names given so get them by reading USERLOG */
210*1014Sbill 
211*1014Sbill 	if(  (i > argc)  ||  fngrlogin  )  {
212*1014Sbill 	    unshort = large;
213*1014Sbill 	    if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
214*1014Sbill 		user.ut_name[0] = NULL;
215*1014Sbill 		while( user.ut_name[0] == NULL )  {
216*1014Sbill 		    if( read( uf, (char *) &user, usize ) != usize )  {
217*1014Sbill 			printf( "\nNo one logged on\n" );
218*1014Sbill 			exit( 0 );
219*1014Sbill 		    }
220*1014Sbill 		}
221*1014Sbill 		person1 = (struct person  *) malloc( persize );
222*1014Sbill 		for( j = 0; j < NMAX; j++ )  {
223*1014Sbill 		    person1->tty[j] = user.ut_line[j];
224*1014Sbill 		    person1->name[j] = user.ut_name[j];
225*1014Sbill 		}
226*1014Sbill 		person1->name[NMAX] = NULL;
227*1014Sbill 		person1->tty[NMAX] = NULL;
228*1014Sbill 		person1->loginat = user.ut_time;
229*1014Sbill 		person1->pwd = NILPWD;
230*1014Sbill 		person1->loggedin = 1;
231*1014Sbill 		numnames++;
232*1014Sbill 		p = person1;
233*1014Sbill 		while( read( uf, (char *) &user, usize ) == usize )  {
234*1014Sbill 		    if( user.ut_name[0] == NULL )  continue;
235*1014Sbill 		    p->link = (struct person  *) malloc( persize );
236*1014Sbill 		    p = p->link;
237*1014Sbill 		    for( j = 0; j < NMAX; j++ )  {
238*1014Sbill 			p->tty[j] = user.ut_line[j];
239*1014Sbill 			p->name[j] = user.ut_name[j];
240*1014Sbill 		    }
241*1014Sbill 		    p->name[NMAX] = NULL;
242*1014Sbill 		    p->tty[NMAX] = NULL;
243*1014Sbill 		    p->loginat = user.ut_time;
244*1014Sbill 		    p->pwd = NILPWD;
245*1014Sbill 		    p->loggedin = 1;
246*1014Sbill 		    numnames++;
247*1014Sbill 		}
248*1014Sbill 		p->link = NILPERS;
249*1014Sbill 		close( uf );
250*1014Sbill 	    }
251*1014Sbill 	    else  {
252*1014Sbill 		fprintf( stderr, "finger: error opening %s\n", USERLOG );
253*1014Sbill 		exit( 2 );
254*1014Sbill 	    }
255*1014Sbill 
256*1014Sbill 		/*  if we are doing it, read /etc/passwd for the useful info */
257*1014Sbill 
258*1014Sbill 	    if( unquick )  {
259*1014Sbill 		setpwent();
260*1014Sbill 		fwopen();
261*1014Sbill 		i = numnames;
262*1014Sbill 		while(  ( (pw = getpwent()) != NILPWD )  &&  ( i > 0 )  )  {
263*1014Sbill 		    p = person1;
264*1014Sbill 		    do  {
265*1014Sbill 			if( p->pwd == NILPWD )  {
266*1014Sbill 			    if(  strcmp( p->name, pw->pw_name ) == 0  )  {
267*1014Sbill 				p->pwd = (struct passwd  *) malloc( pwdsize );
268*1014Sbill 				pwdcopy( p->pwd, pw );
269*1014Sbill 				decode( p );
270*1014Sbill 				i--;
271*1014Sbill 			    }
272*1014Sbill 			}
273*1014Sbill 			p = p->link;
274*1014Sbill 		    }  while( p != NILPERS );
275*1014Sbill 		}
276*1014Sbill 		fwclose();
277*1014Sbill 		endpwent();
278*1014Sbill 	    }
279*1014Sbill 	}
280*1014Sbill 
281*1014Sbill     /* get names from command line and check to see if they're  logged in */
282*1014Sbill 
283*1014Sbill 	else  {
284*1014Sbill 	    unshort = ( small == 1 ? 0 : 1 );
285*1014Sbill 	    i++;
286*1014Sbill 	    person1 = (struct person  *) malloc( persize );
287*1014Sbill 	    strcpy(  person1->name, (argv++)[ 0 ]  );
288*1014Sbill 	    person1->loggedin = 0;
289*1014Sbill 	    person1->pwd = NILPWD;
290*1014Sbill 	    numnames++;
291*1014Sbill 	    p = person1;
292*1014Sbill 	    while( i++ <= argc )  {
293*1014Sbill 		p->link = (struct person  *) malloc( persize );
294*1014Sbill 		p = p->link;
295*1014Sbill 		strcpy(  p->name, (argv++)[ 0 ]  );
296*1014Sbill 		p->loggedin = 0;
297*1014Sbill 		p->pwd = NILPWD;
298*1014Sbill 		numnames++;
299*1014Sbill 	    }
300*1014Sbill 	    p->link = NILPERS;
301*1014Sbill 	    pend = p;
302*1014Sbill 
303*1014Sbill 		/*  if we are doing it, read /etc/passwd for the useful info */
304*1014Sbill 
305*1014Sbill 	    orgnumnames = numnames;
306*1014Sbill 	    if( unquick )  {
307*1014Sbill 		setpwent();
308*1014Sbill 		while(  ( pw = getpwent() ) != NILPWD  )  {
309*1014Sbill 		    p = person1;
310*1014Sbill 		    i = 0;
311*1014Sbill 		    do  {
312*1014Sbill 			if( strcmp( p->name, pw->pw_name ) == 0    ||
313*1014Sbill 			    matchcmp( pw->pw_gecos, pw->pw_name, p->name ) )  {
314*1014Sbill 			    if( p->pwd == NILPWD )  {
315*1014Sbill 				p->pwd = (struct passwd  *) malloc( pwdsize );
316*1014Sbill 				pwdcopy( p->pwd, pw );
317*1014Sbill 			    }
318*1014Sbill 			    else  {	/* handle multiple logins -- append new
319*1014Sbill 					   "duplicate" entry to end of list */
320*1014Sbill 				pend->link = (struct person  *) malloc(persize);
321*1014Sbill 				pend = pend->link;
322*1014Sbill 				pend->link = NILPERS;
323*1014Sbill 				strcpy( pend->name, p->name );
324*1014Sbill 				pend->pwd = (struct passwd  *) malloc(pwdsize);
325*1014Sbill 				pwdcopy( pend->pwd, pw );
326*1014Sbill 				numnames++;
327*1014Sbill 			    }
328*1014Sbill 			}
329*1014Sbill 			p = p->link;
330*1014Sbill 		    }  while( ++i < orgnumnames );
331*1014Sbill 		}
332*1014Sbill 		endpwent();
333*1014Sbill 	    }
334*1014Sbill 
335*1014Sbill 		/*  Now get login information */
336*1014Sbill 
337*1014Sbill 	    if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
338*1014Sbill 		while( read( uf, (char *) &user, usize ) == usize )  {
339*1014Sbill 		    if( user.ut_name[0] == NULL )  continue;
340*1014Sbill 		    p = person1;
341*1014Sbill 		    do  {
342*1014Sbill 			pw = p->pwd;
343*1014Sbill 			if( pw == NILPWD )  {
344*1014Sbill 			    i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX );
345*1014Sbill 			}
346*1014Sbill 			else  {
347*1014Sbill 			    i = 0;
348*1014Sbill 			    while(  (i < NMAX)  &&
349*1014Sbill 				    ( pw->pw_name[i] == user.ut_name[i])  )  {
350*1014Sbill 				if( pw->pw_name[i] == NULL )  {
351*1014Sbill 				    i = NMAX;
352*1014Sbill 				    break;
353*1014Sbill 				}
354*1014Sbill 				i++;
355*1014Sbill 			    }
356*1014Sbill 			}
357*1014Sbill 			if( i == NMAX )  {
358*1014Sbill 			    if( p->loggedin == 1 )  {
359*1014Sbill 				pend->link = (struct person  *) malloc(persize);
360*1014Sbill 				pend = pend->link;
361*1014Sbill 				pend->link = NILPERS;
362*1014Sbill 				strcpy( pend->name, p->name );
363*1014Sbill 				for( j = 0; j < NMAX; j++ )  {
364*1014Sbill 				    pend->tty[j] = user.ut_line[j];
365*1014Sbill 				}
366*1014Sbill 				pend->tty[ NMAX ] = NULL;
367*1014Sbill 				pend->loginat = user.ut_time;
368*1014Sbill 				pend->loggedin = 2;
369*1014Sbill 				if(  pw == NILPWD  )  {
370*1014Sbill 				    pend ->pwd = NILPWD;
371*1014Sbill 				}
372*1014Sbill 				else  {
373*1014Sbill 				    pend->pwd = (struct passwd  *) malloc(pwdsize);
374*1014Sbill 				    pwdcopy( pend->pwd, pw );
375*1014Sbill 				}
376*1014Sbill 				numnames++;
377*1014Sbill 			    }
378*1014Sbill 			    else  {
379*1014Sbill 				if( p->loggedin != 2 )  {
380*1014Sbill 				    for( j = 0; j < NMAX; j++ )  {
381*1014Sbill 					p->tty[j] = user.ut_line[j];
382*1014Sbill 				    }
383*1014Sbill 				    p->tty[ NMAX ] = NULL;
384*1014Sbill 				    p->loginat = user.ut_time;
385*1014Sbill 				    p->loggedin = 1;
386*1014Sbill 				}
387*1014Sbill 			    }
388*1014Sbill 			}
389*1014Sbill 			p = p->link;
390*1014Sbill 		    }  while( p != NILPERS );
391*1014Sbill 		}
392*1014Sbill 		fwopen();
393*1014Sbill 		p = person1;
394*1014Sbill 		while( p != NILPERS )  {
395*1014Sbill 		    if( p->loggedin == 2 )  {
396*1014Sbill 			p->loggedin = 1;
397*1014Sbill 		    }
398*1014Sbill 		    decode( p );
399*1014Sbill 		    p = p->link;
400*1014Sbill 		}
401*1014Sbill 		fwclose();
402*1014Sbill 		close( uf );
403*1014Sbill 	    }
404*1014Sbill 	    else  {
405*1014Sbill 		fprintf( stderr, "finger: error opening %s\n", USERLOG );
406*1014Sbill 		exit( 2 );
407*1014Sbill 	    }
408*1014Sbill 	}
409*1014Sbill 
410*1014Sbill     /* print out what we got */
411*1014Sbill 
412*1014Sbill 	if( header )  {
413*1014Sbill 	    if( unquick )  {
414*1014Sbill 		if( !unshort )  {
415*1014Sbill 		    if( wide )  {
416*1014Sbill 			printf(
417*1014Sbill "Login       Name              TTY Idle    When            Office\n" );
418*1014Sbill 		    }
419*1014Sbill 		    else  {
420*1014Sbill 			printf(
421*1014Sbill "Login    TTY Idle    When            Office\n" );
422*1014Sbill 		    }
423*1014Sbill 		}
424*1014Sbill 	    }
425*1014Sbill 	    else  {
426*1014Sbill 		printf( "Login      TTY            When" );
427*1014Sbill 		if( idle )  {
428*1014Sbill 		    printf( "             Idle" );
429*1014Sbill 		}
430*1014Sbill 		printf( "\n" );
431*1014Sbill 	    }
432*1014Sbill 	}
433*1014Sbill 	p = person1;
434*1014Sbill 	do  {
435*1014Sbill 	    if( unquick )  {
436*1014Sbill 		if( unshort )  {
437*1014Sbill 		    personprint( p );
438*1014Sbill 		    if( p->pwd != NILPWD )  {
439*1014Sbill 			if( hack )  {
440*1014Sbill 			    s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 );
441*1014Sbill 			    strcpy(  s, (p->pwd)->pw_dir  );
442*1014Sbill 			    strcat( s, PROJ );
443*1014Sbill 			    if(  ( fp = fopen( s, "r") )  != NULL  )  {
444*1014Sbill 				printf( "Project: " );
445*1014Sbill 				while(  ( c = getc(fp) )  !=  EOF  )  {
446*1014Sbill 				    if( c == LINEBREAK )  {
447*1014Sbill 					break;
448*1014Sbill 				    }
449*1014Sbill 				    putc( c, stdout );
450*1014Sbill 				}
451*1014Sbill 				fclose( fp );
452*1014Sbill 				printf( "\n" );
453*1014Sbill 			    }
454*1014Sbill 			}
455*1014Sbill 			if( plan )  {
456*1014Sbill 			    s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 );
457*1014Sbill 			    strcpy(  s, (p->pwd)->pw_dir  );
458*1014Sbill 			    strcat( s, PLAN );
459*1014Sbill 			    if(  ( fp = fopen( s, "r") )  == NULL  )  {
460*1014Sbill 				printf( "No Plan.\n" );
461*1014Sbill 			    }
462*1014Sbill 			    else  {
463*1014Sbill 				printf( "Plan:\n" );
464*1014Sbill 				while(  ( c = getc(fp) )  !=  EOF  )  {
465*1014Sbill 				    putc( c, stdout );
466*1014Sbill 				}
467*1014Sbill 				fclose( fp );
468*1014Sbill 			    }
469*1014Sbill 			}
470*1014Sbill 		    }
471*1014Sbill 		    if( p->link != NILPERS )  {
472*1014Sbill 			printf( "\n" );
473*1014Sbill 		    }
474*1014Sbill 		}
475*1014Sbill 		else  {
476*1014Sbill 		    shortprint( p );
477*1014Sbill 		}
478*1014Sbill 	    }
479*1014Sbill 	    else  {
480*1014Sbill 		quickprint( p );
481*1014Sbill 	    }
482*1014Sbill 	    p = p->link;
483*1014Sbill 	}  while( p != NILPERS );
484*1014Sbill 	exit(0);
485*1014Sbill }
486*1014Sbill 
487*1014Sbill 
488*1014Sbill /*  given a pointer to a pwd (pfrom) copy it to another one, allocating
489*1014Sbill  *  space for all the stuff in it.  Note: Only the useful (what the
490*1014Sbill  *  program currently uses) things are copied.
491*1014Sbill  */
492*1014Sbill 
493*1014Sbill pwdcopy( pto, pfrom )		/* copy relevant fields only */
494*1014Sbill 
495*1014Sbill     struct  passwd		*pto,  *pfrom;
496*1014Sbill {
497*1014Sbill 	pto->pw_name = malloc(  strlen( pfrom->pw_name ) + 1  );
498*1014Sbill 	strcpy( pto->pw_name, pfrom->pw_name );
499*1014Sbill 	pto->pw_uid = pfrom->pw_uid;
500*1014Sbill 	pto->pw_gecos = malloc(  strlen( pfrom->pw_gecos ) + 1  );
501*1014Sbill 	strcpy( pto->pw_gecos, pfrom->pw_gecos );
502*1014Sbill 	pto->pw_dir = malloc(  strlen( pfrom->pw_dir ) + 1  );
503*1014Sbill 	strcpy( pto->pw_dir, pfrom->pw_dir );
504*1014Sbill 	pto->pw_shell = malloc(  strlen( pfrom->pw_shell ) + 1  );
505*1014Sbill 	strcpy( pto->pw_shell, pfrom->pw_shell );
506*1014Sbill }
507*1014Sbill 
508*1014Sbill 
509*1014Sbill /*  print out information on quick format giving just name, tty, login time
510*1014Sbill  *  and idle time if idle is set.
511*1014Sbill  */
512*1014Sbill 
513*1014Sbill quickprint( pers )
514*1014Sbill 
515*1014Sbill     struct  person		*pers;
516*1014Sbill {
517*1014Sbill 	int			idleprinted;
518*1014Sbill 
519*1014Sbill 	printf( "%-*.*s", NMAX, NMAX, pers->name );
520*1014Sbill 	printf( "  " );
521*1014Sbill 	if( pers->loggedin )  {
522*1014Sbill 	    if( idle )  {
523*1014Sbill 		findidle( pers );
524*1014Sbill 		if( pers->writeable )  {
525*1014Sbill 		    printf(  " %-*.*s %-16.16s", LMAX, LMAX,
526*1014Sbill 			pers->tty, ctime( &pers->loginat )  );
527*1014Sbill 		}
528*1014Sbill 		else  {
529*1014Sbill 		    printf(  "*%-*.*s %-16.16s", LMAX, LMAX,
530*1014Sbill 			pers->tty, ctime( &pers->loginat )  );
531*1014Sbill 		}
532*1014Sbill 		printf( "   " );
533*1014Sbill 		idleprinted = ltimeprint( &pers->idletime );
534*1014Sbill 	    }
535*1014Sbill 	    else  {
536*1014Sbill 		printf(  " %-*.*s %-16.16s", LMAX, LMAX,
537*1014Sbill 		    pers->tty, ctime( &pers->loginat )  );
538*1014Sbill 	    }
539*1014Sbill 	}
540*1014Sbill 	else  {
541*1014Sbill 	    printf( "          Not Logged In" );
542*1014Sbill 	}
543*1014Sbill 	printf( "\n" );
544*1014Sbill }
545*1014Sbill 
546*1014Sbill 
547*1014Sbill /*  print out information in short format, giving login name, full name,
548*1014Sbill  *  tty, idle time, login time, office location and phone.
549*1014Sbill  */
550*1014Sbill 
551*1014Sbill shortprint( pers )
552*1014Sbill 
553*1014Sbill     struct  person	*pers;
554*1014Sbill 
555*1014Sbill {
556*1014Sbill 	struct  passwd		*pwdt = pers->pwd;
557*1014Sbill 	char			buf[ 26 ];
558*1014Sbill 	int			i,  len,  offset,  dialup;
559*1014Sbill 
560*1014Sbill 	if( pwdt == NILPWD )  {
561*1014Sbill 	    printf( "%-*.*s", NMAX, NMAX,  pers->name );
562*1014Sbill 	    printf( "       ???\n" );
563*1014Sbill 	    return;
564*1014Sbill 	}
565*1014Sbill 	printf( "%-*.*s", NMAX, NMAX,  pwdt->pw_name );
566*1014Sbill 	dialup = 0;
567*1014Sbill 	if( wide )  {
568*1014Sbill 	    if(  strlen( pers->realname ) > 0  )  {
569*1014Sbill 		printf( " %-20.20s", pers->realname );
570*1014Sbill 	    }
571*1014Sbill 	    else  {
572*1014Sbill 		printf( "        ???          " );
573*1014Sbill 	    }
574*1014Sbill 	}
575*1014Sbill 	if( pers->loggedin )  {
576*1014Sbill 	    if( pers->writeable )  {
577*1014Sbill 		printf( "  " );
578*1014Sbill 	    }
579*1014Sbill 	    else  {
580*1014Sbill 		printf( " *" );
581*1014Sbill 	    }
582*1014Sbill 	}
583*1014Sbill 	else  {
584*1014Sbill 	    printf( "  " );
585*1014Sbill 	}
586*1014Sbill 	if(  strlen( pers->tty ) > 0  )  {
587*1014Sbill 	    strcpy( buf, pers->tty );
588*1014Sbill 	    if(  (buf[0] == 't')  &&  (buf[1] == 't')  &&  (buf[2] == 'y')  )  {
589*1014Sbill 		offset = 3;
590*1014Sbill 		for( i = 0; i < 2; i++ )  {
591*1014Sbill 		    buf[i] = buf[i + offset];
592*1014Sbill 		}
593*1014Sbill 	    }
594*1014Sbill 	    if(  (buf[0] == 'd')  &&  pers->loggedin  )  {
595*1014Sbill 		dialup = 1;
596*1014Sbill 	    }
597*1014Sbill 	    printf( "%-2.2s ", buf );
598*1014Sbill 	}
599*1014Sbill 	else  {
600*1014Sbill 	    printf( "   " );
601*1014Sbill 	}
602*1014Sbill 	strcpy( buf, ctime( &pers->loginat ) );
603*1014Sbill 	if( pers->loggedin )  {
604*1014Sbill 	    stimeprint( &pers->idletime );
605*1014Sbill 	    offset = 7;
606*1014Sbill 	    for( i = 4; i < 19; i++ )  {
607*1014Sbill 		buf[i] = buf[i + offset];
608*1014Sbill 	    }
609*1014Sbill 	    printf( " %-9.9s ", buf );
610*1014Sbill 	}
611*1014Sbill 	else  {
612*1014Sbill 	    printf( " " );
613*1014Sbill 	    offset = 4;
614*1014Sbill 	    for( i = 0; i <22; i++ )  {
615*1014Sbill 		buf[i] = buf[i + offset];
616*1014Sbill 	    }
617*1014Sbill 	    printf( "<%-12.12s>", buf );
618*1014Sbill 	}
619*1014Sbill 	len = strlen( pers->homephone );
620*1014Sbill 	if(  dialup  &&  (len > 0)  )  {
621*1014Sbill 	    if( len == 8 )  {
622*1014Sbill 		printf( "             " );
623*1014Sbill 	    }
624*1014Sbill 	    else  {
625*1014Sbill 		if( len == 12 )  {
626*1014Sbill 		    printf( "         " );
627*1014Sbill 		}
628*1014Sbill 		else {
629*1014Sbill 		    for( i = 1; i <= 21 - len; i++ )  {
630*1014Sbill 			printf( " " );
631*1014Sbill 		    }
632*1014Sbill 		}
633*1014Sbill 	    }
634*1014Sbill 	    printf( "%s", pers->homephone );
635*1014Sbill 	}
636*1014Sbill 	else  {
637*1014Sbill 	    if(  strlen( pers->office ) > 0  )  {
638*1014Sbill 		printf( " %-11.11s", pers->office );
639*1014Sbill 		if(  strlen( pers->officephone ) > 0  )  {
640*1014Sbill 		    printf( " %8.8s", pers->officephone );
641*1014Sbill 		}
642*1014Sbill 		else  {
643*1014Sbill 		    if( len == 8 )  {
644*1014Sbill 			printf( " %8.8s", pers->homephone );
645*1014Sbill 		    }
646*1014Sbill 		}
647*1014Sbill 	    }
648*1014Sbill 	    else  {
649*1014Sbill 		if(  strlen( pers->officephone ) > 0  )  {
650*1014Sbill 		    printf( "             %8.8s", pers->officephone );
651*1014Sbill 		}
652*1014Sbill 		else  {
653*1014Sbill 		    if( len == 8 )  {
654*1014Sbill 			printf( "             %8.8s", pers->homephone );
655*1014Sbill 		    }
656*1014Sbill 		    else  {
657*1014Sbill 			if( len == 12 )  {
658*1014Sbill 			    printf( "         %12.12s", pers->homephone );
659*1014Sbill 			}
660*1014Sbill 		    }
661*1014Sbill 		}
662*1014Sbill 	    }
663*1014Sbill 	}
664*1014Sbill 	printf( "\n" );
665*1014Sbill }
666*1014Sbill 
667*1014Sbill 
668*1014Sbill /*  print out a person in long format giving all possible information.
669*1014Sbill  *  directory and shell are inhibited if unbrief is clear.
670*1014Sbill  */
671*1014Sbill 
672*1014Sbill personprint( pers )
673*1014Sbill 
674*1014Sbill     struct  person	*pers;
675*1014Sbill {
676*1014Sbill 	struct  passwd		*pwdt = pers->pwd;
677*1014Sbill 	int			idleprinted;
678*1014Sbill 
679*1014Sbill 	if( pwdt == NILPWD )  {
680*1014Sbill 	    printf( "Login name: %-10s", pers->name );
681*1014Sbill 	    printf( "			" );
682*1014Sbill 	    printf( "In real life: ???\n");
683*1014Sbill 	    return;
684*1014Sbill 	}
685*1014Sbill 	printf( "Login name: %-10s", pwdt->pw_name );
686*1014Sbill 	if( pers->loggedin )  {
687*1014Sbill 	    if( pers->writeable )  {
688*1014Sbill 		printf( "			" );
689*1014Sbill 	    }
690*1014Sbill 	    else  {
691*1014Sbill 		printf( "	(messages off)	" );
692*1014Sbill 	    }
693*1014Sbill 	}
694*1014Sbill 	else  {
695*1014Sbill 	    printf( "			" );
696*1014Sbill 	}
697*1014Sbill 	if(  strlen( pers->realname ) > 0  )  {
698*1014Sbill 	    printf( "In real life: %-s", pers->realname );
699*1014Sbill 	}
700*1014Sbill 	if(  strlen( pers->office ) > 0  )  {
701*1014Sbill 	    printf( "\nOffice: %-.11s", pers->office );
702*1014Sbill 	    if(  strlen( pers->officephone ) > 0  )  {
703*1014Sbill 		printf( ", %s", pers->officephone );
704*1014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
705*1014Sbill 		    printf( "		Home phone: %s", pers->homephone );
706*1014Sbill 		}
707*1014Sbill 		else  {
708*1014Sbill 		    if(  strlen( pers->random ) > 0  )  {
709*1014Sbill 			printf( "	%s", pers->random );
710*1014Sbill 		    }
711*1014Sbill 		}
712*1014Sbill 	    }
713*1014Sbill 	    else  {
714*1014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
715*1014Sbill 		    printf("			Home phone: %s",pers->homephone);
716*1014Sbill 		}
717*1014Sbill 		if(  strlen( pers->random ) > 0  )  {
718*1014Sbill 		    printf( "			%s", pers->random );
719*1014Sbill 		}
720*1014Sbill 	    }
721*1014Sbill 	}
722*1014Sbill 	else  {
723*1014Sbill 	    if(  strlen( pers->officephone ) > 0  )  {
724*1014Sbill 		printf( "\nPhone: %s", pers->officephone );
725*1014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
726*1014Sbill 		    printf( "\n, %s", pers->homephone );
727*1014Sbill 		    if(  strlen( pers->random ) > 0  )  {
728*1014Sbill 			printf( ", %s", pers->random );
729*1014Sbill 		    }
730*1014Sbill 		}
731*1014Sbill 		else  {
732*1014Sbill 		    if(  strlen( pers->random ) > 0  )  {
733*1014Sbill 			printf( "\n, %s", pers->random );
734*1014Sbill 		    }
735*1014Sbill 		}
736*1014Sbill 	    }
737*1014Sbill 	    else  {
738*1014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
739*1014Sbill 		    printf( "\nPhone: %s", pers->homephone );
740*1014Sbill 		    if(  strlen( pers->random ) > 0  )  {
741*1014Sbill 			printf( ", %s", pers->random );
742*1014Sbill 		    }
743*1014Sbill 		}
744*1014Sbill 		else  {
745*1014Sbill 		    if(  strlen( pers->random ) > 0  )  {
746*1014Sbill 			printf( "\n%s", pers->random );
747*1014Sbill 		    }
748*1014Sbill 		}
749*1014Sbill 	    }
750*1014Sbill 	}
751*1014Sbill 	if( unbrief )  {
752*1014Sbill 	    printf( "\n" );
753*1014Sbill 	    printf( "Directory: %-25s", pwdt->pw_dir );
754*1014Sbill 	    if(  strlen( pwdt->pw_shell ) > 0  )  {
755*1014Sbill 		printf( "	Shell: %-s", pwdt->pw_shell );
756*1014Sbill 	    }
757*1014Sbill 	}
758*1014Sbill 	if( pers->loggedin )  {
759*1014Sbill 	    register char *ep = ctime( &pers->loginat );
760*1014Sbill 	    printf("\nOn since %15.15s on %-*.*s	", &ep[4], LMAX, LMAX, pers->tty );
761*1014Sbill 	    idleprinted = ltimeprint( &pers->idletime );
762*1014Sbill 	    if( idleprinted )  {
763*1014Sbill 		printf( " Idle Time" );
764*1014Sbill 	    }
765*1014Sbill 	}
766*1014Sbill 	else  {
767*1014Sbill 	    register char *ep = ctime( &pers->loginat );
768*1014Sbill 	    printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty );
769*1014Sbill 	}
770*1014Sbill 	printf( "\n" );
771*1014Sbill }
772*1014Sbill 
773*1014Sbill 
774*1014Sbill /*
775*1014Sbill  *  very hacky section of code to format phone numbers.  filled with
776*1014Sbill  *  magic constants like 4, 7 and 10.
777*1014Sbill  */
778*1014Sbill 
779*1014Sbill char  *phone( s, len )
780*1014Sbill 
781*1014Sbill     char		*s;
782*1014Sbill     int			len;
783*1014Sbill {
784*1014Sbill 	char		*strsave();
785*1014Sbill 	char		fonebuf[ 15 ];
786*1014Sbill 	int		i;
787*1014Sbill 
788*1014Sbill 	switch(  len  )  {
789*1014Sbill 
790*1014Sbill 	    case  4:
791*1014Sbill 		fonebuf[ 0 ] = ' ';
792*1014Sbill 		fonebuf[ 1 ] = 'x';
793*1014Sbill 		fonebuf[ 2 ] = '2';
794*1014Sbill 		fonebuf[ 3 ] = '-';
795*1014Sbill 		for( i = 0; i <= 3; i++ )  {
796*1014Sbill 		    fonebuf[ 4 + i ] = *s++;
797*1014Sbill 		}
798*1014Sbill 		fonebuf[ 8 ] = NULL;
799*1014Sbill 		return( strsave( &fonebuf[0] ) );
800*1014Sbill 		break;
801*1014Sbill 
802*1014Sbill 	    case  7:
803*1014Sbill 		for( i = 0; i <= 2; i++ )  {
804*1014Sbill 		    fonebuf[ i ] = *s++;
805*1014Sbill 		}
806*1014Sbill 		fonebuf[ 3 ] = '-';
807*1014Sbill 		for( i = 0; i <= 3; i++ )  {
808*1014Sbill 		    fonebuf[ 4 + i ] = *s++;
809*1014Sbill 		}
810*1014Sbill 		fonebuf[ 8 ] = NULL;
811*1014Sbill 		return( strsave( &fonebuf[0] ) );
812*1014Sbill 		break;
813*1014Sbill 
814*1014Sbill 	    case 10:
815*1014Sbill 		for( i = 0; i <= 2; i++ )  {
816*1014Sbill 		    fonebuf[ i ] = *s++;
817*1014Sbill 		}
818*1014Sbill 		fonebuf[ 3 ] = '-';
819*1014Sbill 		for( i = 0; i <= 2; i++ )  {
820*1014Sbill 		    fonebuf[ 4 + i ] = *s++;
821*1014Sbill 		}
822*1014Sbill 		fonebuf[ 7 ] = '-';
823*1014Sbill 		for( i = 0; i <= 3; i++ )  {
824*1014Sbill 		    fonebuf[ 8 + i ] = *s++;
825*1014Sbill 		}
826*1014Sbill 		fonebuf[ 12 ] = NULL;
827*1014Sbill 		return( strsave( &fonebuf[0] ) );
828*1014Sbill 		break;
829*1014Sbill 
830*1014Sbill 	    default:
831*1014Sbill 		fprintf( stderr, "finger: error in phone numbering\n" );
832*1014Sbill 		return( strsave(s) );
833*1014Sbill 		break;
834*1014Sbill 	}
835*1014Sbill }
836*1014Sbill 
837*1014Sbill 
838*1014Sbill /*  decode the information in the gecos field of /etc/passwd
839*1014Sbill  *  another hacky section of code, but given the format the stuff is in...
840*1014Sbill  */
841*1014Sbill 
842*1014Sbill decode( pers )
843*1014Sbill 
844*1014Sbill     struct  person	*pers;
845*1014Sbill 
846*1014Sbill {
847*1014Sbill 	struct  passwd		*pwdt = pers->pwd;
848*1014Sbill 	char			buffer[ 40 ],  *bp,  *gp,  *lp;
849*1014Sbill 	char			*phone();
850*1014Sbill 	int			alldigits;
851*1014Sbill 	int			len;
852*1014Sbill 	int			i;
853*1014Sbill 
854*1014Sbill 	pers->realname = NULLSTR;
855*1014Sbill 	pers->office = NULLSTR;
856*1014Sbill 	pers->officephone = NULLSTR;
857*1014Sbill 	pers->homephone = NULLSTR;
858*1014Sbill 	pers->random = NULLSTR;
859*1014Sbill 	if(  pwdt != NILPWD )  {
860*1014Sbill 	    gp = pwdt->pw_gecos;
861*1014Sbill 	    bp = &buffer[ 0 ];
862*1014Sbill 	    if( *gp == ASTERISK )  {
863*1014Sbill 		gp++;
864*1014Sbill 	    }
865*1014Sbill 	    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {	/* name */
866*1014Sbill 		if( *gp == SAMENAME )  {
867*1014Sbill 		    lp = pwdt->pw_name;
868*1014Sbill 		    *bp++ = CAPITALIZE(*lp++);
869*1014Sbill 		    while( *lp != NULL )  {
870*1014Sbill 			*bp++ = *lp++;
871*1014Sbill 		    }
872*1014Sbill 		}
873*1014Sbill 		else  {
874*1014Sbill 		    *bp++ = *gp;
875*1014Sbill 		}
876*1014Sbill 		gp++;
877*1014Sbill 	    }
878*1014Sbill 	    *bp = NULL;
879*1014Sbill 	    pers->realname = malloc( strlen( &buffer[0] ) + 1 );
880*1014Sbill 	    strcpy( pers->realname, &buffer[0] );
881*1014Sbill 	    if( *gp++ == COMMA )  {			/* office, supposedly */
882*1014Sbill 		alldigits = 1;
883*1014Sbill 		bp = &buffer[ 0 ];
884*1014Sbill 		while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
885*1014Sbill 		    *bp = *gp++;
886*1014Sbill 		    alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
887*1014Sbill 		    bp++;
888*1014Sbill 		}
889*1014Sbill 		*bp = NULL;
890*1014Sbill 		len = strlen( &buffer[0] );
891*1014Sbill 		if( buffer[ len - 1 ]  ==  CORY )  {
892*1014Sbill 		    strcpy( &buffer[ len - 1 ], " Cory" );
893*1014Sbill 		    pers->office = malloc( len + 5 );
894*1014Sbill 		    strcpy( pers->office, &buffer[0] );
895*1014Sbill 		}
896*1014Sbill 		else  {
897*1014Sbill 		    if( buffer[ len - 1 ] == EVANS )  {
898*1014Sbill 			strcpy( &buffer[ len - 1 ], " Evans" );
899*1014Sbill 			pers->office = malloc( len + 6 );
900*1014Sbill 			strcpy( pers->office, &buffer[0] );
901*1014Sbill 		    }
902*1014Sbill 		    else  {
903*1014Sbill 			if( buffer[ len - 1 ] == 'L' )  {
904*1014Sbill 			    strcpy( &buffer[ len - 1 ], " LBL" );
905*1014Sbill 			    pers->office = malloc( len + 4 );
906*1014Sbill 			    strcpy( pers->office, &buffer[0] );
907*1014Sbill 			}
908*1014Sbill 			else  {
909*1014Sbill 			    if( alldigits )  {
910*1014Sbill 				if( len == 4 )  {
911*1014Sbill 				    pers->officephone = phone(&buffer[0], len);
912*1014Sbill 				}
913*1014Sbill 				else  {
914*1014Sbill 				    if(  (len == 7) || (len == 10)  )  {
915*1014Sbill 					pers->homephone = phone(&buffer[0],len);
916*1014Sbill 				    }
917*1014Sbill 				}
918*1014Sbill 			    }
919*1014Sbill 			    else  {
920*1014Sbill 				pers->random = malloc( len + 1 );
921*1014Sbill 				strcpy( pers->random, &buffer[0] );
922*1014Sbill 			    }
923*1014Sbill 			}
924*1014Sbill 		    }
925*1014Sbill 		}
926*1014Sbill 		if( *gp++ == COMMA )  {	    /* office phone, theoretically */
927*1014Sbill 		    bp = &buffer[ 0 ];
928*1014Sbill 		    alldigits = 1;
929*1014Sbill 		    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
930*1014Sbill 			*bp = *gp++;
931*1014Sbill 			alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
932*1014Sbill 			bp++;
933*1014Sbill 		    }
934*1014Sbill 		    *bp = NULL;
935*1014Sbill 		    len = strlen( &buffer[0] );
936*1014Sbill 		    if( alldigits )  {
937*1014Sbill 			if(  len != 4  )  {
938*1014Sbill 			    if(  (len == 7) || (len == 10)  )  {
939*1014Sbill 				pers->homephone = phone( &buffer[0], len );
940*1014Sbill 			    }
941*1014Sbill 			    else  {
942*1014Sbill 				pers->random = malloc( len + 1 );
943*1014Sbill 				strcpy( pers->random, &buffer[0] );
944*1014Sbill 			    }
945*1014Sbill 			}
946*1014Sbill 			else  {
947*1014Sbill 				pers->officephone = phone( &buffer[0], len );
948*1014Sbill 			}
949*1014Sbill 		    }
950*1014Sbill 		    else  {
951*1014Sbill 			pers->random = malloc( len + 1 );
952*1014Sbill 			strcpy( pers->random, &buffer[0] );
953*1014Sbill 		    }
954*1014Sbill 		    if( *gp++ == COMMA )  {		/* home phone?? */
955*1014Sbill 			bp = &buffer[ 0 ];
956*1014Sbill 			alldigits = 1;
957*1014Sbill 			    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
958*1014Sbill 				*bp = *gp++;
959*1014Sbill 				alldigits = alldigits && ('0' <= *bp) &&
960*1014Sbill 							(*bp <= '9');
961*1014Sbill 				bp++;
962*1014Sbill 			    }
963*1014Sbill 			*bp = NULL;
964*1014Sbill 			len = strlen( &buffer[0] );
965*1014Sbill 			if( alldigits  &&  ( (len == 7) || (len == 10) )  )  {
966*1014Sbill 			    if( *pers->homephone != NULL )  {
967*1014Sbill 				pers->officephone = pers->homephone;
968*1014Sbill 			    }
969*1014Sbill 			    pers->homephone = phone( &buffer[0], len );
970*1014Sbill 			}
971*1014Sbill 			else  {
972*1014Sbill 			    pers->random = malloc( strlen( &buffer[0] ) + 1 );
973*1014Sbill 			    strcpy( pers->random, &buffer[0] );
974*1014Sbill 			}
975*1014Sbill 		    }
976*1014Sbill 		}
977*1014Sbill 	    }
978*1014Sbill 	    if( pers->loggedin == 0 )  {
979*1014Sbill 		findwhen( pers );
980*1014Sbill 	    }
981*1014Sbill 	    else  {
982*1014Sbill 		findidle( pers );
983*1014Sbill 	    }
984*1014Sbill 	}
985*1014Sbill }
986*1014Sbill 
987*1014Sbill 
988*1014Sbill /*  find the last log in of a user by checking the LASTLOG file.
989*1014Sbill  *  the entry is indexed by the uid, so this can only be done if
990*1014Sbill  *  the uid is known (which it isn't in quick mode)
991*1014Sbill  */
992*1014Sbill 
993*1014Sbill fwopen()
994*1014Sbill {
995*1014Sbill 	if(  ( lf = open(LASTLOG, 0) ) >= 0  )  {
996*1014Sbill 	    llopenerr = 0;
997*1014Sbill 	}
998*1014Sbill 	else  {
999*1014Sbill 	    fprintf( stderr, "finger: lastlog open error\n" );
1000*1014Sbill 	    llopenerr = 1;
1001*1014Sbill 	}
1002*1014Sbill }
1003*1014Sbill 
1004*1014Sbill 
1005*1014Sbill findwhen( pers )
1006*1014Sbill 
1007*1014Sbill     struct  person	*pers;
1008*1014Sbill {
1009*1014Sbill 	struct  passwd		*pwdt = pers->pwd;
1010*1014Sbill 	struct  lastlog		ll;
1011*1014Sbill 	int			llsize = sizeof ll;
1012*1014Sbill 	int			i;
1013*1014Sbill 
1014*1014Sbill 	if( !llopenerr )  {
1015*1014Sbill 	    lseek( lf, pwdt->pw_uid*llsize, 0 );
1016*1014Sbill 	    if( read( lf, (char *) &ll, llsize ) == llsize )  {
1017*1014Sbill 		    for( i = 0; i < LMAX; i++ )  {
1018*1014Sbill 			pers->tty[ i ] = ll.ll_line[ i ];
1019*1014Sbill 		    }
1020*1014Sbill 		    pers->tty[ LMAX ] = NULL;
1021*1014Sbill 		    pers->loginat = ll.ll_time;
1022*1014Sbill 	    }
1023*1014Sbill 	    else  {
1024*1014Sbill 		fprintf( stderr, "finger: lastlog read error\n" );
1025*1014Sbill 		pers->tty[ 0 ] = NULL;
1026*1014Sbill 		pers->loginat = 0L;
1027*1014Sbill 	    }
1028*1014Sbill 	}
1029*1014Sbill 	else  {
1030*1014Sbill 	    pers->tty[ 0 ] = NULL;
1031*1014Sbill 	    pers->loginat = 0L;
1032*1014Sbill 	}
1033*1014Sbill }
1034*1014Sbill 
1035*1014Sbill 
1036*1014Sbill fwclose()
1037*1014Sbill {
1038*1014Sbill 	if( !llopenerr )  {
1039*1014Sbill 	    close( lf );
1040*1014Sbill 	}
1041*1014Sbill }
1042*1014Sbill 
1043*1014Sbill 
1044*1014Sbill /*  find the idle time of a user by doing a stat on /dev/histty,
1045*1014Sbill  *  where histty has been gotten from USERLOG, supposedly.
1046*1014Sbill  */
1047*1014Sbill 
1048*1014Sbill findidle( pers )
1049*1014Sbill 
1050*1014Sbill     struct  person	*pers;
1051*1014Sbill {
1052*1014Sbill 	struct  stat		ttystatus;
1053*1014Sbill 	struct  passwd		*pwdt = pers->pwd;
1054*1014Sbill 	char			buffer[ 20 ];
1055*1014Sbill 	char			*TTY = "/dev/";
1056*1014Sbill 	int			TTYLEN = strlen( TTY );
1057*1014Sbill 	int			i;
1058*1014Sbill 
1059*1014Sbill 	strcpy( &buffer[0], TTY );
1060*1014Sbill 	i = 0;
1061*1014Sbill 	do  {
1062*1014Sbill 	    buffer[ TTYLEN + i ] = pers->tty[ i ];
1063*1014Sbill 	}  while( ++i <= LMAX );
1064*1014Sbill 	if(  stat( &buffer[0], &ttystatus ) >= 0  )  {
1065*1014Sbill 	    time( &tloc );
1066*1014Sbill 	    if( tloc < ttystatus.st_atime )  {
1067*1014Sbill 		pers->idletime = 0L;
1068*1014Sbill 	    }
1069*1014Sbill 	    else  {
1070*1014Sbill 		pers->idletime = tloc - ttystatus.st_atime;
1071*1014Sbill 	    }
1072*1014Sbill 	    if(  (ttystatus.st_mode & TALKABLE) == TALKABLE  )  {
1073*1014Sbill 		pers->writeable = 1;
1074*1014Sbill 	    }
1075*1014Sbill 	    else  {
1076*1014Sbill 		pers->writeable = 0;
1077*1014Sbill 	    }
1078*1014Sbill 	}
1079*1014Sbill 	else  {
1080*1014Sbill 	    fprintf( stderr, "finger: error STATing %s\n", &buffer[0] );
1081*1014Sbill 	    exit( 4 );
1082*1014Sbill 	}
1083*1014Sbill }
1084*1014Sbill 
1085*1014Sbill 
1086*1014Sbill /*  print idle time in short format; this program always prints 4 characters;
1087*1014Sbill  *  if the idle time is zero, it prints 4 blanks.
1088*1014Sbill  */
1089*1014Sbill 
1090*1014Sbill stimeprint( dt )
1091*1014Sbill 
1092*1014Sbill     long	*dt;
1093*1014Sbill {
1094*1014Sbill 	struct  tm		*gmtime();
1095*1014Sbill 	struct  tm		*delta;
1096*1014Sbill 
1097*1014Sbill 	delta = gmtime( dt );
1098*1014Sbill 	if( delta->tm_yday == 0 )  {
1099*1014Sbill 	    if( delta->tm_hour == 0 )  {
1100*1014Sbill 		if( delta->tm_min >= 10 )  {
1101*1014Sbill 		    printf( " %2.2d ", delta->tm_min );
1102*1014Sbill 		}
1103*1014Sbill 		else  {
1104*1014Sbill 		    if( delta->tm_min == 0 )  {
1105*1014Sbill 			printf( "    " );
1106*1014Sbill 		    }
1107*1014Sbill 		    else  {
1108*1014Sbill 			printf( "  %1.1d ", delta->tm_min );
1109*1014Sbill 		    }
1110*1014Sbill 		}
1111*1014Sbill 	    }
1112*1014Sbill 	    else  {
1113*1014Sbill 		if( delta->tm_hour >= 10 )  {
1114*1014Sbill 		    printf( "%3.3d:", delta->tm_hour );
1115*1014Sbill 		}
1116*1014Sbill 		else  {
1117*1014Sbill 		    printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min );
1118*1014Sbill 		}
1119*1014Sbill 	    }
1120*1014Sbill 	}
1121*1014Sbill 	else  {
1122*1014Sbill 	    printf( "%3dd", delta->tm_yday );
1123*1014Sbill 	}
1124*1014Sbill }
1125*1014Sbill 
1126*1014Sbill 
1127*1014Sbill /*  print idle time in long format with care being taken not to pluralize
1128*1014Sbill  *  1 minutes or 1 hours or 1 days.
1129*1014Sbill  */
1130*1014Sbill 
1131*1014Sbill ltimeprint( dt )
1132*1014Sbill 
1133*1014Sbill     long	*dt;
1134*1014Sbill {
1135*1014Sbill 	struct  tm		*gmtime();
1136*1014Sbill 	struct  tm		*delta;
1137*1014Sbill 	int			printed = 1;
1138*1014Sbill 
1139*1014Sbill 	delta = gmtime( dt );
1140*1014Sbill 	if( delta->tm_yday == 0 )  {
1141*1014Sbill 	    if( delta->tm_hour == 0 )  {
1142*1014Sbill 		if( delta->tm_min >= 10 )  {
1143*1014Sbill 		    printf( "%2d minutes", delta->tm_min );
1144*1014Sbill 		}
1145*1014Sbill 		else  {
1146*1014Sbill 		    if( delta->tm_min == 0 )  {
1147*1014Sbill 			if( delta->tm_sec > 10 )  {
1148*1014Sbill 			    printf( "%2d seconds", delta->tm_sec );
1149*1014Sbill 			}
1150*1014Sbill 			else  {
1151*1014Sbill 			    printed = 0;
1152*1014Sbill 			}
1153*1014Sbill 		    }
1154*1014Sbill 		    else  {
1155*1014Sbill 			if( delta->tm_min == 1 )  {
1156*1014Sbill 			    if( delta->tm_sec == 1 )  {
1157*1014Sbill 				printf( "%1d minute %1d second",
1158*1014Sbill 				    delta->tm_min, delta->tm_sec );
1159*1014Sbill 			    }
1160*1014Sbill 			    else  {
1161*1014Sbill 				printf( "%1d minute %d seconds",
1162*1014Sbill 				    delta->tm_min, delta->tm_sec );
1163*1014Sbill 			    }
1164*1014Sbill 			}
1165*1014Sbill 			else  {
1166*1014Sbill 			    if( delta->tm_sec == 1 )  {
1167*1014Sbill 				printf( "%1d minutes %1d second",
1168*1014Sbill 				    delta->tm_min, delta->tm_sec );
1169*1014Sbill 			    }
1170*1014Sbill 			    else  {
1171*1014Sbill 				printf( "%1d minutes %d seconds",
1172*1014Sbill 				    delta->tm_min, delta->tm_sec );
1173*1014Sbill 			    }
1174*1014Sbill 			}
1175*1014Sbill 		    }
1176*1014Sbill 		}
1177*1014Sbill 	    }
1178*1014Sbill 	    else  {
1179*1014Sbill 		if( delta->tm_hour >= 10 )  {
1180*1014Sbill 		    printf( "%2d hours", delta->tm_hour );
1181*1014Sbill 		}
1182*1014Sbill 		else  {
1183*1014Sbill 		    if( delta->tm_hour == 1 )  {
1184*1014Sbill 			if( delta->tm_min == 1 )  {
1185*1014Sbill 			    printf( "%1d hour %1d minute",
1186*1014Sbill 				delta->tm_hour, delta->tm_min );
1187*1014Sbill 			}
1188*1014Sbill 			else  {
1189*1014Sbill 			    printf( "%1d hour %2d minutes",
1190*1014Sbill 				delta->tm_hour, delta->tm_min );
1191*1014Sbill 			}
1192*1014Sbill 		    }
1193*1014Sbill 		    else  {
1194*1014Sbill 			if( delta->tm_min == 1 )  {
1195*1014Sbill 			    printf( "%1d hours %1d minute",
1196*1014Sbill 				delta->tm_hour, delta->tm_min );
1197*1014Sbill 			}
1198*1014Sbill 			else  {
1199*1014Sbill 			    printf( "%1d hours %2d minutes",
1200*1014Sbill 				delta->tm_hour, delta->tm_min );
1201*1014Sbill 			}
1202*1014Sbill 		    }
1203*1014Sbill 		}
1204*1014Sbill 	    }
1205*1014Sbill 	}
1206*1014Sbill 	else  {
1207*1014Sbill 		if( delta->tm_yday >= 10 )  {
1208*1014Sbill 		    printf( "%2d days", delta->tm_yday );
1209*1014Sbill 		}
1210*1014Sbill 		else  {
1211*1014Sbill 		    if( delta->tm_yday == 1 )  {
1212*1014Sbill 			if( delta->tm_hour == 1 )  {
1213*1014Sbill 			    printf( "%1d day %1d hour",
1214*1014Sbill 				delta->tm_yday, delta->tm_hour );
1215*1014Sbill 			}
1216*1014Sbill 			else  {
1217*1014Sbill 			    printf( "%1d day %2d hours",
1218*1014Sbill 				delta->tm_yday, delta->tm_hour );
1219*1014Sbill 			}
1220*1014Sbill 		    }
1221*1014Sbill 		    else  {
1222*1014Sbill 			if( delta->tm_hour == 1 )  {
1223*1014Sbill 			    printf( "%1d days %1d hour",
1224*1014Sbill 				delta->tm_yday, delta->tm_hour );
1225*1014Sbill 			}
1226*1014Sbill 			else  {
1227*1014Sbill 			    printf( "%1d days %2d hours",
1228*1014Sbill 				delta->tm_yday, delta->tm_hour );
1229*1014Sbill 			}
1230*1014Sbill 		    }
1231*1014Sbill 		}
1232*1014Sbill 	}
1233*1014Sbill 	return( printed );
1234*1014Sbill }
1235*1014Sbill 
1236*1014Sbill 
1237*1014Sbill matchcmp( gname, login, given )
1238*1014Sbill 
1239*1014Sbill     char		*gname;
1240*1014Sbill     char		*login;
1241*1014Sbill     char		*given;
1242*1014Sbill {
1243*1014Sbill 	char		buffer[ 20 ];
1244*1014Sbill 	char		c;
1245*1014Sbill 	int		flag,  i,  unfound;
1246*1014Sbill 
1247*1014Sbill 	if( !match )  {
1248*1014Sbill 	    return( 0 );
1249*1014Sbill 	}
1250*1014Sbill 	else  {
1251*1014Sbill 	    if(  namecmp( login, given )  )  {
1252*1014Sbill 		return( 1 );
1253*1014Sbill 	    }
1254*1014Sbill 	    else  {
1255*1014Sbill 		if( *gname == ASTERISK )  {
1256*1014Sbill 		    gname++;
1257*1014Sbill 		}
1258*1014Sbill 		flag = 1;
1259*1014Sbill 		i = 0;
1260*1014Sbill 		unfound = 1;
1261*1014Sbill 		while(  unfound  )  {
1262*1014Sbill 		    if( flag )  {
1263*1014Sbill 			c = *gname++;
1264*1014Sbill 			if( c == SAMENAME )  {
1265*1014Sbill 			    flag = 0;
1266*1014Sbill 			    c = *login++;
1267*1014Sbill 			}
1268*1014Sbill 			else  {
1269*1014Sbill 			    unfound = (*gname != COMMA)  &&  (*gname != NULL);
1270*1014Sbill 			}
1271*1014Sbill 		    }
1272*1014Sbill 		    else {
1273*1014Sbill 			c = *login++;
1274*1014Sbill 			if( c == NULL )  {
1275*1014Sbill 			    if(  (*gname == COMMA)  ||  (*gname == NULL)  )  {
1276*1014Sbill 				break;
1277*1014Sbill 			    }
1278*1014Sbill 			    else  {
1279*1014Sbill 				flag = 1;
1280*1014Sbill 				continue;
1281*1014Sbill 			    }
1282*1014Sbill 			}
1283*1014Sbill 		    }
1284*1014Sbill 		    if( c == BLANK )  {
1285*1014Sbill 			buffer[i++] = NULL;
1286*1014Sbill 			if(  namecmp( buffer, given )  )  {
1287*1014Sbill 			    return( 1 );
1288*1014Sbill 			}
1289*1014Sbill 			i = 0;
1290*1014Sbill 			flag = 1;
1291*1014Sbill 		    }
1292*1014Sbill 		    else  {
1293*1014Sbill 			buffer[ i++ ] = c;
1294*1014Sbill 		    }
1295*1014Sbill 		}
1296*1014Sbill 		buffer[i++] = NULL;
1297*1014Sbill 		if(  namecmp( buffer, given )  )  {
1298*1014Sbill 		    return( 1 );
1299*1014Sbill 		}
1300*1014Sbill 		else  {
1301*1014Sbill 		    return( 0 );
1302*1014Sbill 		}
1303*1014Sbill 	    }
1304*1014Sbill 	}
1305*1014Sbill }
1306*1014Sbill 
1307*1014Sbill 
1308*1014Sbill namecmp( name1, name2 )
1309*1014Sbill 
1310*1014Sbill     char		*name1;
1311*1014Sbill     char		*name2;
1312*1014Sbill {
1313*1014Sbill 	char		c1,  c2;
1314*1014Sbill 
1315*1014Sbill 	c1 = *name1;
1316*1014Sbill 	if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) )  {
1317*1014Sbill 	    c1 = CAPITALIZE( c1 );
1318*1014Sbill 	}
1319*1014Sbill 	c2 = *name2;
1320*1014Sbill 	if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) )  {
1321*1014Sbill 	    c2 = CAPITALIZE( c2 );
1322*1014Sbill 	}
1323*1014Sbill 	while( c1 == c2 )  {
1324*1014Sbill 	    if( c1 == NULL )  {
1325*1014Sbill 		return( 1 );
1326*1014Sbill 	    }
1327*1014Sbill 	    c1 = *++name1;
1328*1014Sbill 	    if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) )  {
1329*1014Sbill 		c1 = CAPITALIZE( c1 );
1330*1014Sbill 	    }
1331*1014Sbill 	    c2 = *++name2;
1332*1014Sbill 	    if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) )  {
1333*1014Sbill 		c2 = CAPITALIZE( c2 );
1334*1014Sbill 	    }
1335*1014Sbill 	}
1336*1014Sbill 	if( *name1 == NULL )  {
1337*1014Sbill 	    while(  ('0' <= *name2)  &&  (*name2 <= '9')  )  {
1338*1014Sbill 		name2++;
1339*1014Sbill 	    }
1340*1014Sbill 	    if( *name2 == NULL )  {
1341*1014Sbill 		return( 1 );
1342*1014Sbill 	    }
1343*1014Sbill 	}
1344*1014Sbill 	else  {
1345*1014Sbill 	    if( *name2 == NULL )  {
1346*1014Sbill 		while(  ('0' <= *name1)  &&  (*name1 <= '9')  )  {
1347*1014Sbill 		    name1++;
1348*1014Sbill 		}
1349*1014Sbill 		if( *name1 == NULL )  {
1350*1014Sbill 		    return( 1 );
1351*1014Sbill 		}
1352*1014Sbill 	    }
1353*1014Sbill 	}
1354*1014Sbill 	return( 0 );
1355*1014Sbill }
1356*1014Sbill 
1357*1014Sbill 
1358*1014Sbill char  *strsave( s )
1359*1014Sbill 
1360*1014Sbill     char		*s;
1361*1014Sbill {
1362*1014Sbill 	char		*malloc();
1363*1014Sbill 	char		*p;
1364*1014Sbill 
1365*1014Sbill 	p = malloc( strlen( s ) + 1 );
1366*1014Sbill 	strcpy( p, s );
1367*1014Sbill }
1368