xref: /csrg-svn/usr.bin/finger/finger.c (revision 16469)
113619Ssam #ifndef lint
2*16469Ssam static char *sccsid = "@(#)finger.c	4.6 (Berkeley) 05/11/84";
313619Ssam #endif
41014Sbill 
51014Sbill /*  This is a finger program.  It prints out useful information about users
61014Sbill  *  by digging it up from various system files.  It is not very portable
71014Sbill  *  because the most useful parts of the information (the full user name,
81014Sbill  *  office, and phone numbers) are all stored in the VAX-unused gecos field
91014Sbill  *  of /etc/passwd, which, unfortunately, other UNIXes use for other things.
101014Sbill  *
111014Sbill  *  There are three output formats, all of which give login name, teletype
121014Sbill  *  line number, and login time.  The short output format is reminiscent
131014Sbill  *  of finger on ITS, and gives one line of information per user containing
141014Sbill  *  in addition to the minimum basic requirements (MBR), the full name of
151014Sbill  *  the user, his idle time and office location and phone number.  The
161014Sbill  *  quick style output is UNIX who-like, giving only name, teletype and
171014Sbill  *  login time.  Finally, the long style output give the same information
181014Sbill  *  as the short (in more legible format), the home directory and shell
191014Sbill  *  of the user, and, if it exits, a copy of the file .plan in the users
201014Sbill  *  home directory.  Finger may be called with or without a list of people
211014Sbill  *  to finger -- if no list is given, all the people currently logged in
221014Sbill  *  are fingered.
231014Sbill  *
241014Sbill  *  The program is validly called by one of the following:
251014Sbill  *
261014Sbill  *	finger			{short form list of users}
271014Sbill  *	finger -l		{long form list of users}
281014Sbill  *	finger -b		{briefer long form list of users}
291014Sbill  *	finger -q		{quick list of users}
301014Sbill  *	finger -i		{quick list of users with idle times}
311014Sbill  *	finger namelist		{long format list of specified users}
321014Sbill  *	finger -s namelist	{short format list of specified users}
331014Sbill  *	finger -w namelist	{narrow short format list of specified users}
341014Sbill  *
351014Sbill  *  where 'namelist' is a list of users login names.
361014Sbill  *  The other options can all be given after one '-', or each can have its
371014Sbill  *  own '-'.  The -f option disables the printing of headers for short and
381014Sbill  *  quick outputs.  The -b option briefens long format outputs.  The -p
391014Sbill  *  option turns off plans for long format outputs.
401014Sbill  */
411014Sbill 
421014Sbill #include	<sys/types.h>
431014Sbill #include	<sys/stat.h>
441014Sbill #include	<sgtty.h>
451014Sbill #include	<utmp.h>
461014Sbill #include	<signal.h>
471014Sbill #include	<pwd.h>
481014Sbill #include	<stdio.h>
491014Sbill #include	<lastlog.h>
5013619Ssam #include	<sys/time.h>
51*16469Ssam #include	<sys/socket.h>
52*16469Ssam #include	<netinet/in.h>
53*16469Ssam #include	<netdb.h>
541014Sbill 
551014Sbill struct	utmp	utmp;	/* for sizeof */
561014Sbill #define NMAX sizeof(utmp.ut_name)
571014Sbill #define LMAX sizeof(utmp.ut_line)
581014Sbill 
591014Sbill #define		ASTERISK	'*'	/* ignore this in real name */
601014Sbill #define		BLANK		' '	/* blank character (i.e. space) */
611014Sbill #define		CAPITALIZE	0137&	/* capitalize character macro */
621014Sbill #define		COMMA		','	/* separator in pw_gecos field */
631014Sbill #define		COMMAND		'-'	/* command line flag char */
641014Sbill #define		CORY		'C'	/* cory hall office */
651014Sbill #define		EVANS		'E'	/* evans hall office */
661014Sbill #define		LINEBREAK	012	/* line feed */
671014Sbill #define		NULLSTR		""	/* the null string, opposed to NULL */
681014Sbill #define		SAMENAME	'&'	/* repeat login name in real name */
691014Sbill #define		TALKABLE	0222	/* tty is writeable if 222 mode */
701014Sbill 
711014Sbill struct  person  {			/* one for each person fingered */
721014Sbill 	char		name[NMAX+1];	/* login name */
731014Sbill 	char		tty[LMAX+1];	/* NULL terminated tty line */
741014Sbill 	long		loginat;	/* time of login (possibly last) */
751014Sbill 	long		idletime;	/* how long idle (if logged in) */
761014Sbill 	short int	loggedin;	/* flag for being logged in */
771014Sbill 	short int	writeable;	/* flag for tty being writeable */
781014Sbill 	char		*realname;	/* pointer to full name */
791014Sbill 	char		*office;	/* pointer to office name */
801014Sbill 	char		*officephone;	/* pointer to office phone no. */
811014Sbill 	char		*homephone;	/* pointer to home phone no. */
821014Sbill 	char		*random;	/* for any random stuff in pw_gecos */
831014Sbill 	struct  passwd	*pwd;		/* structure of /etc/passwd stuff */
841014Sbill 	struct  person	*link;		/* link to next person */
851014Sbill };
861014Sbill 
871014Sbill struct  passwd			*NILPWD = 0;
881014Sbill struct  person			*NILPERS = 0;
891014Sbill 
901014Sbill int		persize		= sizeof( struct person );
911014Sbill int		pwdsize		= sizeof( struct passwd );
921014Sbill 
931014Sbill char		LASTLOG[]	= "/usr/adm/lastlog";	/* last login info */
941014Sbill char		USERLOG[]	= "/etc/utmp";		/* who is logged in */
951014Sbill char		outbuf[BUFSIZ];				/* output buffer */
961014Sbill char		*ctime();
971014Sbill 
981014Sbill int		unbrief		= 1;		/* -b option default */
991014Sbill int		header		= 1;		/* -f option default */
1001014Sbill int		hack		= 1;		/* -h option default */
1011014Sbill int		idle		= 0;		/* -i option default */
1021014Sbill int		large		= 0;		/* -l option default */
1031014Sbill int		match		= 1;		/* -m option default */
1041014Sbill int		plan		= 1;		/* -p option default */
1051014Sbill int		unquick		= 1;		/* -q option default */
1061014Sbill int		small		= 0;		/* -s option default */
1071014Sbill int		wide		= 1;		/* -w option default */
1081014Sbill 
1091014Sbill int		lf;
1101014Sbill int		llopenerr;
1111014Sbill 
1121014Sbill long		tloc;				/* current time */
1131014Sbill 
1141014Sbill 
1151014Sbill 
1161014Sbill main( argc, argv )
1171014Sbill 
1181014Sbill     int		argc;
1191014Sbill     char	*argv[];
1201014Sbill 
1211014Sbill {
1221014Sbill 	FILE			*fp,  *fopen();		/* for plans */
1231014Sbill 	struct  passwd		*getpwent();		/* read /etc/passwd */
1241014Sbill 	struct  person		*person1,  *p,  *pend;	/* people */
1251014Sbill 	struct  passwd		*pw;			/* temporary */
1261014Sbill 	struct  utmp		user;			/*   ditto   */
1271014Sbill 	char			*malloc();
1281014Sbill 	char			*s,  *pn,  *ln;
1291014Sbill 	char			c;
1301014Sbill 	char			*PLAN = "/.plan";	/* what plan file is */
1311014Sbill 	char			*PROJ = "/.project";	/* what project file */
1321014Sbill 	int			PLANLEN = strlen( PLAN );
1331014Sbill 	int			PROJLEN = strlen( PROJ );
1341014Sbill 	int			numnames = 0;
1351014Sbill 	int			orgnumnames;
1361014Sbill 	int			uf;
1371014Sbill 	int			usize = sizeof user;
1381014Sbill 	int			unshort;
1391014Sbill 	int			i, j;
1401014Sbill 	int			fngrlogin;
1411014Sbill 
1421014Sbill 	setbuf( stdout, outbuf );			/* buffer output */
1431014Sbill 
1441014Sbill     /*  parse command line for (optional) arguments */
1451014Sbill 
1461014Sbill 	i = 1;
1471014Sbill 	if(  strcmp( *argv, "sh" )  )  {
1481014Sbill 	    fngrlogin = 0;
1491014Sbill 	    while( i++ < argc  &&  (*++argv)[0] == COMMAND )  {
1501014Sbill 		for( s = argv[0] + 1; *s != NULL; s++ )  {
1511014Sbill 			switch  (*s)  {
1521014Sbill 
1531014Sbill 			    case 'b':
1541014Sbill 				    unbrief = 0;
1551014Sbill 				    break;
1561014Sbill 
1571014Sbill 			    case 'f':
1581014Sbill 				    header = 0;
1591014Sbill 				    break;
1601014Sbill 
1611014Sbill 			    case 'h':
1621014Sbill 				    hack = 0;
1631014Sbill 				    break;
1641014Sbill 
1651014Sbill 			    case 'i':
1661014Sbill 				    idle = 1;
1671014Sbill 				    unquick = 0;
1681014Sbill 				    break;
1691014Sbill 
1701014Sbill 			    case 'l':
1711014Sbill 				    large = 1;
1721014Sbill 				    break;
1731014Sbill 
1741014Sbill 			    case 'm':
1751014Sbill 				    match = 0;
1761014Sbill 				    break;
1771014Sbill 
1781014Sbill 			    case 'p':
1791014Sbill 				    plan = 0;
1801014Sbill 				    break;
1811014Sbill 
1821014Sbill 			    case 'q':
1831014Sbill 				    unquick = 0;
1841014Sbill 				    break;
1851014Sbill 
1861014Sbill 			    case 's':
1871014Sbill 				    small = 1;
1881014Sbill 				    break;
1891014Sbill 
1901014Sbill 			    case 'w':
1911014Sbill 				    wide = 0;
1921014Sbill 				    break;
1931014Sbill 
1941014Sbill 			    default:
1951014Sbill 				fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" );
1961014Sbill 				exit( 1 );
1971014Sbill 			}
1981014Sbill 		}
1991014Sbill 	    }
2001014Sbill 	}
2011014Sbill 	else  {
2021014Sbill 	    fngrlogin = 1;
2031014Sbill 	}
2041014Sbill 	if( unquick )  {
2051014Sbill 	    time( &tloc );
2061014Sbill 	}
2071014Sbill 	else  {
2081014Sbill 	    if( idle )  {
2091014Sbill 		time( &tloc );
2101014Sbill 	    }
2111014Sbill 	}
2121014Sbill 
2131014Sbill     /*  i > argc means no login names given so get them by reading USERLOG */
2141014Sbill 
2151014Sbill 	if(  (i > argc)  ||  fngrlogin  )  {
2161014Sbill 	    unshort = large;
2171014Sbill 	    if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
2181014Sbill 		user.ut_name[0] = NULL;
2191014Sbill 		while( user.ut_name[0] == NULL )  {
2201014Sbill 		    if( read( uf, (char *) &user, usize ) != usize )  {
221*16469Ssam 			printf( "No one logged on\n" );
2221014Sbill 			exit( 0 );
2231014Sbill 		    }
2241014Sbill 		}
2251014Sbill 		person1 = (struct person  *) malloc( persize );
2261014Sbill 		for( j = 0; j < NMAX; j++ )  {
2271014Sbill 		    person1->tty[j] = user.ut_line[j];
2281014Sbill 		    person1->name[j] = user.ut_name[j];
2291014Sbill 		}
2301014Sbill 		person1->name[NMAX] = NULL;
2311014Sbill 		person1->tty[NMAX] = NULL;
2321014Sbill 		person1->loginat = user.ut_time;
2331014Sbill 		person1->pwd = NILPWD;
2341014Sbill 		person1->loggedin = 1;
2351014Sbill 		numnames++;
2361014Sbill 		p = person1;
2371014Sbill 		while( read( uf, (char *) &user, usize ) == usize )  {
2381014Sbill 		    if( user.ut_name[0] == NULL )  continue;
2391014Sbill 		    p->link = (struct person  *) malloc( persize );
2401014Sbill 		    p = p->link;
2411014Sbill 		    for( j = 0; j < NMAX; j++ )  {
2421014Sbill 			p->tty[j] = user.ut_line[j];
2431014Sbill 			p->name[j] = user.ut_name[j];
2441014Sbill 		    }
2451014Sbill 		    p->name[NMAX] = NULL;
2461014Sbill 		    p->tty[NMAX] = NULL;
2471014Sbill 		    p->loginat = user.ut_time;
2481014Sbill 		    p->pwd = NILPWD;
2491014Sbill 		    p->loggedin = 1;
2501014Sbill 		    numnames++;
2511014Sbill 		}
2521014Sbill 		p->link = NILPERS;
2531014Sbill 		close( uf );
2541014Sbill 	    }
2551014Sbill 	    else  {
2561014Sbill 		fprintf( stderr, "finger: error opening %s\n", USERLOG );
2571014Sbill 		exit( 2 );
2581014Sbill 	    }
2591014Sbill 
2601014Sbill 		/*  if we are doing it, read /etc/passwd for the useful info */
2611014Sbill 
2621014Sbill 	    if( unquick )  {
2631014Sbill 		setpwent();
2641014Sbill 		fwopen();
2651014Sbill 		i = numnames;
2661014Sbill 		while(  ( (pw = getpwent()) != NILPWD )  &&  ( i > 0 )  )  {
2671014Sbill 		    p = person1;
2681014Sbill 		    do  {
2691014Sbill 			if( p->pwd == NILPWD )  {
2701014Sbill 			    if(  strcmp( p->name, pw->pw_name ) == 0  )  {
2711014Sbill 				p->pwd = (struct passwd  *) malloc( pwdsize );
2721014Sbill 				pwdcopy( p->pwd, pw );
2731014Sbill 				decode( p );
2741014Sbill 				i--;
2751014Sbill 			    }
2761014Sbill 			}
2771014Sbill 			p = p->link;
2781014Sbill 		    }  while( p != NILPERS );
2791014Sbill 		}
2801014Sbill 		fwclose();
2811014Sbill 		endpwent();
2821014Sbill 	    }
2831014Sbill 	}
2841014Sbill 
2851014Sbill     /* get names from command line and check to see if they're  logged in */
2861014Sbill 
2871014Sbill 	else  {
2881014Sbill 	    unshort = ( small == 1 ? 0 : 1 );
289*16469Ssam 	    while (i <= argc && netfinger(*argv)) {
290*16469Ssam 		i++;
291*16469Ssam 		argv++;
292*16469Ssam 	    }
293*16469Ssam 	    if (i++ > argc)
294*16469Ssam 		exit(0);
2951014Sbill 	    person1 = (struct person  *) malloc( persize );
2961014Sbill 	    strcpy(  person1->name, (argv++)[ 0 ]  );
2971014Sbill 	    person1->loggedin = 0;
2981014Sbill 	    person1->pwd = NILPWD;
2991014Sbill 	    numnames++;
3001014Sbill 	    p = person1;
3011014Sbill 	    while( i++ <= argc )  {
302*16469Ssam 		if (netfinger(*argv)) {
303*16469Ssam 		    argv++;
304*16469Ssam 		    continue;
305*16469Ssam 		}
3061014Sbill 		p->link = (struct person  *) malloc( persize );
3071014Sbill 		p = p->link;
3081014Sbill 		strcpy(  p->name, (argv++)[ 0 ]  );
3091014Sbill 		p->loggedin = 0;
3101014Sbill 		p->pwd = NILPWD;
3111014Sbill 		numnames++;
3121014Sbill 	    }
3131014Sbill 	    p->link = NILPERS;
3141014Sbill 	    pend = p;
3151014Sbill 
3161014Sbill 		/*  if we are doing it, read /etc/passwd for the useful info */
3171014Sbill 
3181014Sbill 	    orgnumnames = numnames;
3191014Sbill 	    if( unquick )  {
3201014Sbill 		setpwent();
3211014Sbill 		while(  ( pw = getpwent() ) != NILPWD  )  {
3221014Sbill 		    p = person1;
3231014Sbill 		    i = 0;
3241014Sbill 		    do  {
3251014Sbill 			if( strcmp( p->name, pw->pw_name ) == 0    ||
3261014Sbill 			    matchcmp( pw->pw_gecos, pw->pw_name, p->name ) )  {
3271014Sbill 			    if( p->pwd == NILPWD )  {
3281014Sbill 				p->pwd = (struct passwd  *) malloc( pwdsize );
3291014Sbill 				pwdcopy( p->pwd, pw );
3301014Sbill 			    }
3311014Sbill 			    else  {	/* handle multiple logins -- append new
3321014Sbill 					   "duplicate" entry to end of list */
3331014Sbill 				pend->link = (struct person  *) malloc(persize);
3341014Sbill 				pend = pend->link;
3351014Sbill 				pend->link = NILPERS;
3361014Sbill 				strcpy( pend->name, p->name );
3371014Sbill 				pend->pwd = (struct passwd  *) malloc(pwdsize);
3381014Sbill 				pwdcopy( pend->pwd, pw );
3391014Sbill 				numnames++;
3401014Sbill 			    }
3411014Sbill 			}
3421014Sbill 			p = p->link;
3431014Sbill 		    }  while( ++i < orgnumnames );
3441014Sbill 		}
3451014Sbill 		endpwent();
3461014Sbill 	    }
3471014Sbill 
3481014Sbill 		/*  Now get login information */
3491014Sbill 
3501014Sbill 	    if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
3511014Sbill 		while( read( uf, (char *) &user, usize ) == usize )  {
3521014Sbill 		    if( user.ut_name[0] == NULL )  continue;
3531014Sbill 		    p = person1;
3541014Sbill 		    do  {
3551014Sbill 			pw = p->pwd;
3561014Sbill 			if( pw == NILPWD )  {
3571014Sbill 			    i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX );
3581014Sbill 			}
3591014Sbill 			else  {
3601014Sbill 			    i = 0;
3611014Sbill 			    while(  (i < NMAX)  &&
3621014Sbill 				    ( pw->pw_name[i] == user.ut_name[i])  )  {
3631014Sbill 				if( pw->pw_name[i] == NULL )  {
3641014Sbill 				    i = NMAX;
3651014Sbill 				    break;
3661014Sbill 				}
3671014Sbill 				i++;
3681014Sbill 			    }
3691014Sbill 			}
3701014Sbill 			if( i == NMAX )  {
3711014Sbill 			    if( p->loggedin == 1 )  {
3721014Sbill 				pend->link = (struct person  *) malloc(persize);
3731014Sbill 				pend = pend->link;
3741014Sbill 				pend->link = NILPERS;
3751014Sbill 				strcpy( pend->name, p->name );
3761014Sbill 				for( j = 0; j < NMAX; j++ )  {
3771014Sbill 				    pend->tty[j] = user.ut_line[j];
3781014Sbill 				}
3791014Sbill 				pend->tty[ NMAX ] = NULL;
3801014Sbill 				pend->loginat = user.ut_time;
3811014Sbill 				pend->loggedin = 2;
3821014Sbill 				if(  pw == NILPWD  )  {
3831014Sbill 				    pend ->pwd = NILPWD;
3841014Sbill 				}
3851014Sbill 				else  {
3861014Sbill 				    pend->pwd = (struct passwd  *) malloc(pwdsize);
3871014Sbill 				    pwdcopy( pend->pwd, pw );
3881014Sbill 				}
3891014Sbill 				numnames++;
3901014Sbill 			    }
3911014Sbill 			    else  {
3921014Sbill 				if( p->loggedin != 2 )  {
3931014Sbill 				    for( j = 0; j < NMAX; j++ )  {
3941014Sbill 					p->tty[j] = user.ut_line[j];
3951014Sbill 				    }
3961014Sbill 				    p->tty[ NMAX ] = NULL;
3971014Sbill 				    p->loginat = user.ut_time;
3981014Sbill 				    p->loggedin = 1;
3991014Sbill 				}
4001014Sbill 			    }
4011014Sbill 			}
4021014Sbill 			p = p->link;
4031014Sbill 		    }  while( p != NILPERS );
4041014Sbill 		}
4051014Sbill 		fwopen();
4061014Sbill 		p = person1;
4071014Sbill 		while( p != NILPERS )  {
4081014Sbill 		    if( p->loggedin == 2 )  {
4091014Sbill 			p->loggedin = 1;
4101014Sbill 		    }
4111014Sbill 		    decode( p );
4121014Sbill 		    p = p->link;
4131014Sbill 		}
4141014Sbill 		fwclose();
4151014Sbill 		close( uf );
4161014Sbill 	    }
4171014Sbill 	    else  {
4181014Sbill 		fprintf( stderr, "finger: error opening %s\n", USERLOG );
4191014Sbill 		exit( 2 );
4201014Sbill 	    }
4211014Sbill 	}
4221014Sbill 
4231014Sbill     /* print out what we got */
4241014Sbill 
4251014Sbill 	if( header )  {
4261014Sbill 	    if( unquick )  {
4271014Sbill 		if( !unshort )  {
4281014Sbill 		    if( wide )  {
4291014Sbill 			printf(
4301014Sbill "Login       Name              TTY Idle    When            Office\n" );
4311014Sbill 		    }
4321014Sbill 		    else  {
4331014Sbill 			printf(
4341014Sbill "Login    TTY Idle    When            Office\n" );
4351014Sbill 		    }
4361014Sbill 		}
4371014Sbill 	    }
4381014Sbill 	    else  {
4391014Sbill 		printf( "Login      TTY            When" );
4401014Sbill 		if( idle )  {
4411014Sbill 		    printf( "             Idle" );
4421014Sbill 		}
4431014Sbill 		printf( "\n" );
4441014Sbill 	    }
4451014Sbill 	}
4461014Sbill 	p = person1;
4471014Sbill 	do  {
4481014Sbill 	    if( unquick )  {
4491014Sbill 		if( unshort )  {
4501014Sbill 		    personprint( p );
4511014Sbill 		    if( p->pwd != NILPWD )  {
4521014Sbill 			if( hack )  {
4531014Sbill 			    s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 );
4541014Sbill 			    strcpy(  s, (p->pwd)->pw_dir  );
4551014Sbill 			    strcat( s, PROJ );
4561014Sbill 			    if(  ( fp = fopen( s, "r") )  != NULL  )  {
4571014Sbill 				printf( "Project: " );
4581014Sbill 				while(  ( c = getc(fp) )  !=  EOF  )  {
4591014Sbill 				    if( c == LINEBREAK )  {
4601014Sbill 					break;
4611014Sbill 				    }
4621014Sbill 				    putc( c, stdout );
4631014Sbill 				}
4641014Sbill 				fclose( fp );
4651014Sbill 				printf( "\n" );
4661014Sbill 			    }
4671014Sbill 			}
4681014Sbill 			if( plan )  {
4691014Sbill 			    s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 );
4701014Sbill 			    strcpy(  s, (p->pwd)->pw_dir  );
4711014Sbill 			    strcat( s, PLAN );
4721014Sbill 			    if(  ( fp = fopen( s, "r") )  == NULL  )  {
4731014Sbill 				printf( "No Plan.\n" );
4741014Sbill 			    }
4751014Sbill 			    else  {
4761014Sbill 				printf( "Plan:\n" );
4771014Sbill 				while(  ( c = getc(fp) )  !=  EOF  )  {
4781014Sbill 				    putc( c, stdout );
4791014Sbill 				}
4801014Sbill 				fclose( fp );
4811014Sbill 			    }
4821014Sbill 			}
4831014Sbill 		    }
4841014Sbill 		    if( p->link != NILPERS )  {
4851014Sbill 			printf( "\n" );
4861014Sbill 		    }
4871014Sbill 		}
4881014Sbill 		else  {
4891014Sbill 		    shortprint( p );
4901014Sbill 		}
4911014Sbill 	    }
4921014Sbill 	    else  {
4931014Sbill 		quickprint( p );
4941014Sbill 	    }
4951014Sbill 	    p = p->link;
4961014Sbill 	}  while( p != NILPERS );
4971014Sbill 	exit(0);
4981014Sbill }
4991014Sbill 
5001014Sbill 
5011014Sbill /*  given a pointer to a pwd (pfrom) copy it to another one, allocating
5021014Sbill  *  space for all the stuff in it.  Note: Only the useful (what the
5031014Sbill  *  program currently uses) things are copied.
5041014Sbill  */
5051014Sbill 
5061014Sbill pwdcopy( pto, pfrom )		/* copy relevant fields only */
5071014Sbill 
5081014Sbill     struct  passwd		*pto,  *pfrom;
5091014Sbill {
5101014Sbill 	pto->pw_name = malloc(  strlen( pfrom->pw_name ) + 1  );
5111014Sbill 	strcpy( pto->pw_name, pfrom->pw_name );
5121014Sbill 	pto->pw_uid = pfrom->pw_uid;
5131014Sbill 	pto->pw_gecos = malloc(  strlen( pfrom->pw_gecos ) + 1  );
5141014Sbill 	strcpy( pto->pw_gecos, pfrom->pw_gecos );
5151014Sbill 	pto->pw_dir = malloc(  strlen( pfrom->pw_dir ) + 1  );
5161014Sbill 	strcpy( pto->pw_dir, pfrom->pw_dir );
5171014Sbill 	pto->pw_shell = malloc(  strlen( pfrom->pw_shell ) + 1  );
5181014Sbill 	strcpy( pto->pw_shell, pfrom->pw_shell );
5191014Sbill }
5201014Sbill 
5211014Sbill 
5221014Sbill /*  print out information on quick format giving just name, tty, login time
5231014Sbill  *  and idle time if idle is set.
5241014Sbill  */
5251014Sbill 
5261014Sbill quickprint( pers )
5271014Sbill 
5281014Sbill     struct  person		*pers;
5291014Sbill {
5301014Sbill 	int			idleprinted;
5311014Sbill 
5321014Sbill 	printf( "%-*.*s", NMAX, NMAX, pers->name );
5331014Sbill 	printf( "  " );
5341014Sbill 	if( pers->loggedin )  {
5351014Sbill 	    if( idle )  {
5361014Sbill 		findidle( pers );
5371014Sbill 		if( pers->writeable )  {
5381014Sbill 		    printf(  " %-*.*s %-16.16s", LMAX, LMAX,
5391014Sbill 			pers->tty, ctime( &pers->loginat )  );
5401014Sbill 		}
5411014Sbill 		else  {
5421014Sbill 		    printf(  "*%-*.*s %-16.16s", LMAX, LMAX,
5431014Sbill 			pers->tty, ctime( &pers->loginat )  );
5441014Sbill 		}
5451014Sbill 		printf( "   " );
5461014Sbill 		idleprinted = ltimeprint( &pers->idletime );
5471014Sbill 	    }
5481014Sbill 	    else  {
5491014Sbill 		printf(  " %-*.*s %-16.16s", LMAX, LMAX,
5501014Sbill 		    pers->tty, ctime( &pers->loginat )  );
5511014Sbill 	    }
5521014Sbill 	}
5531014Sbill 	else  {
5541014Sbill 	    printf( "          Not Logged In" );
5551014Sbill 	}
5561014Sbill 	printf( "\n" );
5571014Sbill }
5581014Sbill 
5591014Sbill 
5601014Sbill /*  print out information in short format, giving login name, full name,
5611014Sbill  *  tty, idle time, login time, office location and phone.
5621014Sbill  */
5631014Sbill 
5641014Sbill shortprint( pers )
5651014Sbill 
5661014Sbill     struct  person	*pers;
5671014Sbill 
5681014Sbill {
5691014Sbill 	struct  passwd		*pwdt = pers->pwd;
5701014Sbill 	char			buf[ 26 ];
5711014Sbill 	int			i,  len,  offset,  dialup;
5721014Sbill 
5731014Sbill 	if( pwdt == NILPWD )  {
5741014Sbill 	    printf( "%-*.*s", NMAX, NMAX,  pers->name );
5751014Sbill 	    printf( "       ???\n" );
5761014Sbill 	    return;
5771014Sbill 	}
5781014Sbill 	printf( "%-*.*s", NMAX, NMAX,  pwdt->pw_name );
5791014Sbill 	dialup = 0;
5801014Sbill 	if( wide )  {
5811014Sbill 	    if(  strlen( pers->realname ) > 0  )  {
5821014Sbill 		printf( " %-20.20s", pers->realname );
5831014Sbill 	    }
5841014Sbill 	    else  {
5851014Sbill 		printf( "        ???          " );
5861014Sbill 	    }
5871014Sbill 	}
5881014Sbill 	if( pers->loggedin )  {
5891014Sbill 	    if( pers->writeable )  {
5901014Sbill 		printf( "  " );
5911014Sbill 	    }
5921014Sbill 	    else  {
5931014Sbill 		printf( " *" );
5941014Sbill 	    }
5951014Sbill 	}
5961014Sbill 	else  {
5971014Sbill 	    printf( "  " );
5981014Sbill 	}
5991014Sbill 	if(  strlen( pers->tty ) > 0  )  {
6001014Sbill 	    strcpy( buf, pers->tty );
6011014Sbill 	    if(  (buf[0] == 't')  &&  (buf[1] == 't')  &&  (buf[2] == 'y')  )  {
6021014Sbill 		offset = 3;
6031014Sbill 		for( i = 0; i < 2; i++ )  {
6041014Sbill 		    buf[i] = buf[i + offset];
6051014Sbill 		}
6061014Sbill 	    }
6071014Sbill 	    if(  (buf[0] == 'd')  &&  pers->loggedin  )  {
6081014Sbill 		dialup = 1;
6091014Sbill 	    }
6101014Sbill 	    printf( "%-2.2s ", buf );
6111014Sbill 	}
6121014Sbill 	else  {
6131014Sbill 	    printf( "   " );
6141014Sbill 	}
6158842Smckusick 	strcpy(buf, ctime(&pers->loginat));
6161014Sbill 	if( pers->loggedin )  {
6171014Sbill 	    stimeprint( &pers->idletime );
6181014Sbill 	    offset = 7;
6191014Sbill 	    for( i = 4; i < 19; i++ )  {
6201014Sbill 		buf[i] = buf[i + offset];
6211014Sbill 	    }
6221014Sbill 	    printf( " %-9.9s ", buf );
6231014Sbill 	}
6248842Smckusick 	else if (pers->loginat == 0)
6258842Smckusick 	    printf(" < .  .  .  . >");
6268842Smckusick 	else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
6278842Smckusick 	    printf( " <%-6.6s, %-4.4s>", buf+4, buf+20 );
6288842Smckusick 	else
6298842Smckusick 	    printf(" <%-12.12s>", buf+4);
6301014Sbill 	len = strlen( pers->homephone );
6311014Sbill 	if(  dialup  &&  (len > 0)  )  {
6321014Sbill 	    if( len == 8 )  {
6331014Sbill 		printf( "             " );
6341014Sbill 	    }
6351014Sbill 	    else  {
6361014Sbill 		if( len == 12 )  {
6371014Sbill 		    printf( "         " );
6381014Sbill 		}
6391014Sbill 		else {
6401014Sbill 		    for( i = 1; i <= 21 - len; i++ )  {
6411014Sbill 			printf( " " );
6421014Sbill 		    }
6431014Sbill 		}
6441014Sbill 	    }
6451014Sbill 	    printf( "%s", pers->homephone );
6461014Sbill 	}
6471014Sbill 	else  {
6481014Sbill 	    if(  strlen( pers->office ) > 0  )  {
6491014Sbill 		printf( " %-11.11s", pers->office );
6501014Sbill 		if(  strlen( pers->officephone ) > 0  )  {
6511014Sbill 		    printf( " %8.8s", pers->officephone );
6521014Sbill 		}
6531014Sbill 		else  {
6541014Sbill 		    if( len == 8 )  {
6551014Sbill 			printf( " %8.8s", pers->homephone );
6561014Sbill 		    }
6571014Sbill 		}
6581014Sbill 	    }
6591014Sbill 	    else  {
6601014Sbill 		if(  strlen( pers->officephone ) > 0  )  {
6611014Sbill 		    printf( "             %8.8s", pers->officephone );
6621014Sbill 		}
6631014Sbill 		else  {
6641014Sbill 		    if( len == 8 )  {
6651014Sbill 			printf( "             %8.8s", pers->homephone );
6661014Sbill 		    }
6671014Sbill 		    else  {
6681014Sbill 			if( len == 12 )  {
6691014Sbill 			    printf( "         %12.12s", pers->homephone );
6701014Sbill 			}
6711014Sbill 		    }
6721014Sbill 		}
6731014Sbill 	    }
6741014Sbill 	}
6751014Sbill 	printf( "\n" );
6761014Sbill }
6771014Sbill 
6781014Sbill 
6791014Sbill /*  print out a person in long format giving all possible information.
6801014Sbill  *  directory and shell are inhibited if unbrief is clear.
6811014Sbill  */
6821014Sbill 
6831014Sbill personprint( pers )
6841014Sbill 
6851014Sbill     struct  person	*pers;
6861014Sbill {
6871014Sbill 	struct  passwd		*pwdt = pers->pwd;
6881014Sbill 	int			idleprinted;
6891014Sbill 
6901014Sbill 	if( pwdt == NILPWD )  {
6911014Sbill 	    printf( "Login name: %-10s", pers->name );
6921014Sbill 	    printf( "			" );
6931014Sbill 	    printf( "In real life: ???\n");
6941014Sbill 	    return;
6951014Sbill 	}
6961014Sbill 	printf( "Login name: %-10s", pwdt->pw_name );
6971014Sbill 	if( pers->loggedin )  {
6981014Sbill 	    if( pers->writeable )  {
6991014Sbill 		printf( "			" );
7001014Sbill 	    }
7011014Sbill 	    else  {
7021014Sbill 		printf( "	(messages off)	" );
7031014Sbill 	    }
7041014Sbill 	}
7051014Sbill 	else  {
7061014Sbill 	    printf( "			" );
7071014Sbill 	}
7081014Sbill 	if(  strlen( pers->realname ) > 0  )  {
7091014Sbill 	    printf( "In real life: %-s", pers->realname );
7101014Sbill 	}
7111014Sbill 	if(  strlen( pers->office ) > 0  )  {
7121014Sbill 	    printf( "\nOffice: %-.11s", pers->office );
7131014Sbill 	    if(  strlen( pers->officephone ) > 0  )  {
7141014Sbill 		printf( ", %s", pers->officephone );
7151014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
7161014Sbill 		    printf( "		Home phone: %s", pers->homephone );
7171014Sbill 		}
7181014Sbill 		else  {
7191014Sbill 		    if(  strlen( pers->random ) > 0  )  {
7201014Sbill 			printf( "	%s", pers->random );
7211014Sbill 		    }
7221014Sbill 		}
7231014Sbill 	    }
7241014Sbill 	    else  {
7251014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
7261014Sbill 		    printf("			Home phone: %s",pers->homephone);
7271014Sbill 		}
7281014Sbill 		if(  strlen( pers->random ) > 0  )  {
7291014Sbill 		    printf( "			%s", pers->random );
7301014Sbill 		}
7311014Sbill 	    }
7321014Sbill 	}
7331014Sbill 	else  {
7341014Sbill 	    if(  strlen( pers->officephone ) > 0  )  {
7351014Sbill 		printf( "\nPhone: %s", pers->officephone );
7361014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
7371014Sbill 		    printf( "\n, %s", pers->homephone );
7381014Sbill 		    if(  strlen( pers->random ) > 0  )  {
7391014Sbill 			printf( ", %s", pers->random );
7401014Sbill 		    }
7411014Sbill 		}
7421014Sbill 		else  {
7431014Sbill 		    if(  strlen( pers->random ) > 0  )  {
7441014Sbill 			printf( "\n, %s", pers->random );
7451014Sbill 		    }
7461014Sbill 		}
7471014Sbill 	    }
7481014Sbill 	    else  {
7491014Sbill 		if(  strlen( pers->homephone ) > 0  )  {
7501014Sbill 		    printf( "\nPhone: %s", pers->homephone );
7511014Sbill 		    if(  strlen( pers->random ) > 0  )  {
7521014Sbill 			printf( ", %s", pers->random );
7531014Sbill 		    }
7541014Sbill 		}
7551014Sbill 		else  {
7561014Sbill 		    if(  strlen( pers->random ) > 0  )  {
7571014Sbill 			printf( "\n%s", pers->random );
7581014Sbill 		    }
7591014Sbill 		}
7601014Sbill 	    }
7611014Sbill 	}
7621014Sbill 	if( unbrief )  {
7631014Sbill 	    printf( "\n" );
7641014Sbill 	    printf( "Directory: %-25s", pwdt->pw_dir );
7651014Sbill 	    if(  strlen( pwdt->pw_shell ) > 0  )  {
7661014Sbill 		printf( "	Shell: %-s", pwdt->pw_shell );
7671014Sbill 	    }
7681014Sbill 	}
7691014Sbill 	if( pers->loggedin )  {
7701014Sbill 	    register char *ep = ctime( &pers->loginat );
7711014Sbill 	    printf("\nOn since %15.15s on %-*.*s	", &ep[4], LMAX, LMAX, pers->tty );
7721014Sbill 	    idleprinted = ltimeprint( &pers->idletime );
7731014Sbill 	    if( idleprinted )  {
7741014Sbill 		printf( " Idle Time" );
7751014Sbill 	    }
7761014Sbill 	}
7778842Smckusick 	else if (pers->loginat == 0)
7788842Smckusick 	    printf("\nNever logged in.");
7798842Smckusick 	else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
7808842Smckusick 	    register char *ep = ctime( &pers->loginat );
7818842Smckusick 	    printf("\nLast login %10.10s, %4.4s on %.*s", ep, ep+20, LMAX, pers->tty);
7828842Smckusick 	}
7831014Sbill 	else  {
7841014Sbill 	    register char *ep = ctime( &pers->loginat );
7851014Sbill 	    printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty );
7861014Sbill 	}
7871014Sbill 	printf( "\n" );
7881014Sbill }
7891014Sbill 
7901014Sbill 
7911014Sbill /*
7921014Sbill  *  very hacky section of code to format phone numbers.  filled with
7931014Sbill  *  magic constants like 4, 7 and 10.
7941014Sbill  */
7951014Sbill 
7961014Sbill char  *phone( s, len )
7971014Sbill 
7981014Sbill     char		*s;
7991014Sbill     int			len;
8001014Sbill {
8011014Sbill 	char		*strsave();
8021014Sbill 	char		fonebuf[ 15 ];
8031014Sbill 	int		i;
8041014Sbill 
8051014Sbill 	switch(  len  )  {
8061014Sbill 
8071014Sbill 	    case  4:
8081014Sbill 		fonebuf[ 0 ] = ' ';
8091014Sbill 		fonebuf[ 1 ] = 'x';
8101014Sbill 		fonebuf[ 2 ] = '2';
8111014Sbill 		fonebuf[ 3 ] = '-';
8121014Sbill 		for( i = 0; i <= 3; i++ )  {
8131014Sbill 		    fonebuf[ 4 + i ] = *s++;
8141014Sbill 		}
8151014Sbill 		fonebuf[ 8 ] = NULL;
8161014Sbill 		return( strsave( &fonebuf[0] ) );
8171014Sbill 		break;
8181014Sbill 
8191014Sbill 	    case  7:
8201014Sbill 		for( i = 0; i <= 2; i++ )  {
8211014Sbill 		    fonebuf[ i ] = *s++;
8221014Sbill 		}
8231014Sbill 		fonebuf[ 3 ] = '-';
8241014Sbill 		for( i = 0; i <= 3; i++ )  {
8251014Sbill 		    fonebuf[ 4 + i ] = *s++;
8261014Sbill 		}
8271014Sbill 		fonebuf[ 8 ] = NULL;
8281014Sbill 		return( strsave( &fonebuf[0] ) );
8291014Sbill 		break;
8301014Sbill 
8311014Sbill 	    case 10:
8321014Sbill 		for( i = 0; i <= 2; i++ )  {
8331014Sbill 		    fonebuf[ i ] = *s++;
8341014Sbill 		}
8351014Sbill 		fonebuf[ 3 ] = '-';
8361014Sbill 		for( i = 0; i <= 2; i++ )  {
8371014Sbill 		    fonebuf[ 4 + i ] = *s++;
8381014Sbill 		}
8391014Sbill 		fonebuf[ 7 ] = '-';
8401014Sbill 		for( i = 0; i <= 3; i++ )  {
8411014Sbill 		    fonebuf[ 8 + i ] = *s++;
8421014Sbill 		}
8431014Sbill 		fonebuf[ 12 ] = NULL;
8441014Sbill 		return( strsave( &fonebuf[0] ) );
8451014Sbill 		break;
8461014Sbill 
8471014Sbill 	    default:
8481014Sbill 		fprintf( stderr, "finger: error in phone numbering\n" );
8491014Sbill 		return( strsave(s) );
8501014Sbill 		break;
8511014Sbill 	}
8521014Sbill }
8531014Sbill 
8541014Sbill 
8551014Sbill /*  decode the information in the gecos field of /etc/passwd
8561014Sbill  *  another hacky section of code, but given the format the stuff is in...
8571014Sbill  */
8581014Sbill 
8591014Sbill decode( pers )
8601014Sbill 
8611014Sbill     struct  person	*pers;
8621014Sbill 
8631014Sbill {
8641014Sbill 	struct  passwd		*pwdt = pers->pwd;
86515001Sralph 	char			buffer[ 256 ],  *bp,  *gp,  *lp;
8661014Sbill 	char			*phone();
8671014Sbill 	int			alldigits;
8681014Sbill 	int			len;
8691014Sbill 	int			i;
8701014Sbill 
8711014Sbill 	pers->realname = NULLSTR;
8721014Sbill 	pers->office = NULLSTR;
8731014Sbill 	pers->officephone = NULLSTR;
8741014Sbill 	pers->homephone = NULLSTR;
8751014Sbill 	pers->random = NULLSTR;
8761014Sbill 	if(  pwdt != NILPWD )  {
8771014Sbill 	    gp = pwdt->pw_gecos;
8781014Sbill 	    bp = &buffer[ 0 ];
8791014Sbill 	    if( *gp == ASTERISK )  {
8801014Sbill 		gp++;
8811014Sbill 	    }
8821014Sbill 	    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {	/* name */
8831014Sbill 		if( *gp == SAMENAME )  {
8841014Sbill 		    lp = pwdt->pw_name;
8851014Sbill 		    *bp++ = CAPITALIZE(*lp++);
8861014Sbill 		    while( *lp != NULL )  {
8871014Sbill 			*bp++ = *lp++;
8881014Sbill 		    }
8891014Sbill 		}
8901014Sbill 		else  {
8911014Sbill 		    *bp++ = *gp;
8921014Sbill 		}
8931014Sbill 		gp++;
8941014Sbill 	    }
8951014Sbill 	    *bp = NULL;
8961014Sbill 	    pers->realname = malloc( strlen( &buffer[0] ) + 1 );
8971014Sbill 	    strcpy( pers->realname, &buffer[0] );
8981014Sbill 	    if( *gp++ == COMMA )  {			/* office, supposedly */
8991014Sbill 		alldigits = 1;
9001014Sbill 		bp = &buffer[ 0 ];
9011014Sbill 		while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
9021014Sbill 		    *bp = *gp++;
9031014Sbill 		    alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
9041014Sbill 		    bp++;
9051014Sbill 		}
9061014Sbill 		*bp = NULL;
9071014Sbill 		len = strlen( &buffer[0] );
9081014Sbill 		if( buffer[ len - 1 ]  ==  CORY )  {
9091014Sbill 		    strcpy( &buffer[ len - 1 ], " Cory" );
9101014Sbill 		    pers->office = malloc( len + 5 );
9111014Sbill 		    strcpy( pers->office, &buffer[0] );
9121014Sbill 		}
9131014Sbill 		else  {
9141014Sbill 		    if( buffer[ len - 1 ] == EVANS )  {
9151014Sbill 			strcpy( &buffer[ len - 1 ], " Evans" );
9161014Sbill 			pers->office = malloc( len + 6 );
9171014Sbill 			strcpy( pers->office, &buffer[0] );
9181014Sbill 		    }
9191014Sbill 		    else  {
9201014Sbill 			if( buffer[ len - 1 ] == 'L' )  {
9211014Sbill 			    strcpy( &buffer[ len - 1 ], " LBL" );
9221014Sbill 			    pers->office = malloc( len + 4 );
9231014Sbill 			    strcpy( pers->office, &buffer[0] );
9241014Sbill 			}
9251014Sbill 			else  {
9261014Sbill 			    if( alldigits )  {
9271014Sbill 				if( len == 4 )  {
9281014Sbill 				    pers->officephone = phone(&buffer[0], len);
9291014Sbill 				}
9301014Sbill 				else  {
9311014Sbill 				    if(  (len == 7) || (len == 10)  )  {
9321014Sbill 					pers->homephone = phone(&buffer[0],len);
9331014Sbill 				    }
9341014Sbill 				}
9351014Sbill 			    }
9361014Sbill 			    else  {
9371014Sbill 				pers->random = malloc( len + 1 );
9381014Sbill 				strcpy( pers->random, &buffer[0] );
9391014Sbill 			    }
9401014Sbill 			}
9411014Sbill 		    }
9421014Sbill 		}
9431014Sbill 		if( *gp++ == COMMA )  {	    /* office phone, theoretically */
9441014Sbill 		    bp = &buffer[ 0 ];
9451014Sbill 		    alldigits = 1;
9461014Sbill 		    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
9471014Sbill 			*bp = *gp++;
9481014Sbill 			alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
9491014Sbill 			bp++;
9501014Sbill 		    }
9511014Sbill 		    *bp = NULL;
9521014Sbill 		    len = strlen( &buffer[0] );
9531014Sbill 		    if( alldigits )  {
9541014Sbill 			if(  len != 4  )  {
9551014Sbill 			    if(  (len == 7) || (len == 10)  )  {
9561014Sbill 				pers->homephone = phone( &buffer[0], len );
9571014Sbill 			    }
9581014Sbill 			    else  {
9591014Sbill 				pers->random = malloc( len + 1 );
9601014Sbill 				strcpy( pers->random, &buffer[0] );
9611014Sbill 			    }
9621014Sbill 			}
9631014Sbill 			else  {
9641014Sbill 				pers->officephone = phone( &buffer[0], len );
9651014Sbill 			}
9661014Sbill 		    }
9671014Sbill 		    else  {
9681014Sbill 			pers->random = malloc( len + 1 );
9691014Sbill 			strcpy( pers->random, &buffer[0] );
9701014Sbill 		    }
9711014Sbill 		    if( *gp++ == COMMA )  {		/* home phone?? */
9721014Sbill 			bp = &buffer[ 0 ];
9731014Sbill 			alldigits = 1;
9741014Sbill 			    while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
9751014Sbill 				*bp = *gp++;
9761014Sbill 				alldigits = alldigits && ('0' <= *bp) &&
9771014Sbill 							(*bp <= '9');
9781014Sbill 				bp++;
9791014Sbill 			    }
9801014Sbill 			*bp = NULL;
9811014Sbill 			len = strlen( &buffer[0] );
9821014Sbill 			if( alldigits  &&  ( (len == 7) || (len == 10) )  )  {
9831014Sbill 			    if( *pers->homephone != NULL )  {
9841014Sbill 				pers->officephone = pers->homephone;
9851014Sbill 			    }
9861014Sbill 			    pers->homephone = phone( &buffer[0], len );
9871014Sbill 			}
9881014Sbill 			else  {
9891014Sbill 			    pers->random = malloc( strlen( &buffer[0] ) + 1 );
9901014Sbill 			    strcpy( pers->random, &buffer[0] );
9911014Sbill 			}
9921014Sbill 		    }
9931014Sbill 		}
9941014Sbill 	    }
9951014Sbill 	    if( pers->loggedin == 0 )  {
9961014Sbill 		findwhen( pers );
9971014Sbill 	    }
9981014Sbill 	    else  {
9991014Sbill 		findidle( pers );
10001014Sbill 	    }
10011014Sbill 	}
10021014Sbill }
10031014Sbill 
10041014Sbill 
10051014Sbill /*  find the last log in of a user by checking the LASTLOG file.
10061014Sbill  *  the entry is indexed by the uid, so this can only be done if
10071014Sbill  *  the uid is known (which it isn't in quick mode)
10081014Sbill  */
10091014Sbill 
10101014Sbill fwopen()
10111014Sbill {
10121014Sbill 	if(  ( lf = open(LASTLOG, 0) ) >= 0  )  {
10131014Sbill 	    llopenerr = 0;
10141014Sbill 	}
10151014Sbill 	else  {
10161014Sbill 	    fprintf( stderr, "finger: lastlog open error\n" );
10171014Sbill 	    llopenerr = 1;
10181014Sbill 	}
10191014Sbill }
10201014Sbill 
10211014Sbill 
10221014Sbill findwhen( pers )
10231014Sbill 
10241014Sbill     struct  person	*pers;
10251014Sbill {
10261014Sbill 	struct  passwd		*pwdt = pers->pwd;
10271014Sbill 	struct  lastlog		ll;
10281014Sbill 	int			llsize = sizeof ll;
10291014Sbill 	int			i;
10301014Sbill 
10311014Sbill 	if( !llopenerr )  {
10321014Sbill 	    lseek( lf, pwdt->pw_uid*llsize, 0 );
10338842Smckusick 	    if ((i = read( lf, (char *) &ll, llsize )) == llsize) {
10341014Sbill 		    for( i = 0; i < LMAX; i++ )  {
10351014Sbill 			pers->tty[ i ] = ll.ll_line[ i ];
10361014Sbill 		    }
10371014Sbill 		    pers->tty[ LMAX ] = NULL;
10381014Sbill 		    pers->loginat = ll.ll_time;
10391014Sbill 	    }
10401014Sbill 	    else  {
10418842Smckusick 		if (i != 0)
10428842Smckusick 			fprintf(stderr, "finger: lastlog read error\n");
10431014Sbill 		pers->tty[ 0 ] = NULL;
10441014Sbill 		pers->loginat = 0L;
10451014Sbill 	    }
10461014Sbill 	}
10471014Sbill 	else  {
10481014Sbill 	    pers->tty[ 0 ] = NULL;
10491014Sbill 	    pers->loginat = 0L;
10501014Sbill 	}
10511014Sbill }
10521014Sbill 
10531014Sbill 
10541014Sbill fwclose()
10551014Sbill {
10561014Sbill 	if( !llopenerr )  {
10571014Sbill 	    close( lf );
10581014Sbill 	}
10591014Sbill }
10601014Sbill 
10611014Sbill 
10621014Sbill /*  find the idle time of a user by doing a stat on /dev/histty,
10631014Sbill  *  where histty has been gotten from USERLOG, supposedly.
10641014Sbill  */
10651014Sbill 
10661014Sbill findidle( pers )
10671014Sbill 
10681014Sbill     struct  person	*pers;
10691014Sbill {
10701014Sbill 	struct  stat		ttystatus;
10711014Sbill 	struct  passwd		*pwdt = pers->pwd;
10721014Sbill 	char			buffer[ 20 ];
10731014Sbill 	char			*TTY = "/dev/";
10741014Sbill 	int			TTYLEN = strlen( TTY );
10751014Sbill 	int			i;
10761014Sbill 
10771014Sbill 	strcpy( &buffer[0], TTY );
10781014Sbill 	i = 0;
10791014Sbill 	do  {
10801014Sbill 	    buffer[ TTYLEN + i ] = pers->tty[ i ];
10811014Sbill 	}  while( ++i <= LMAX );
10821014Sbill 	if(  stat( &buffer[0], &ttystatus ) >= 0  )  {
10831014Sbill 	    time( &tloc );
10841014Sbill 	    if( tloc < ttystatus.st_atime )  {
10851014Sbill 		pers->idletime = 0L;
10861014Sbill 	    }
10871014Sbill 	    else  {
10881014Sbill 		pers->idletime = tloc - ttystatus.st_atime;
10891014Sbill 	    }
10901014Sbill 	    if(  (ttystatus.st_mode & TALKABLE) == TALKABLE  )  {
10911014Sbill 		pers->writeable = 1;
10921014Sbill 	    }
10931014Sbill 	    else  {
10941014Sbill 		pers->writeable = 0;
10951014Sbill 	    }
10961014Sbill 	}
10971014Sbill 	else  {
10981014Sbill 	    fprintf( stderr, "finger: error STATing %s\n", &buffer[0] );
10991014Sbill 	    exit( 4 );
11001014Sbill 	}
11011014Sbill }
11021014Sbill 
11031014Sbill 
11041014Sbill /*  print idle time in short format; this program always prints 4 characters;
11051014Sbill  *  if the idle time is zero, it prints 4 blanks.
11061014Sbill  */
11071014Sbill 
11081014Sbill stimeprint( dt )
11091014Sbill 
11101014Sbill     long	*dt;
11111014Sbill {
11121014Sbill 	struct  tm		*gmtime();
11131014Sbill 	struct  tm		*delta;
11141014Sbill 
11151014Sbill 	delta = gmtime( dt );
11161014Sbill 	if( delta->tm_yday == 0 )  {
11171014Sbill 	    if( delta->tm_hour == 0 )  {
11181014Sbill 		if( delta->tm_min >= 10 )  {
11191014Sbill 		    printf( " %2.2d ", delta->tm_min );
11201014Sbill 		}
11211014Sbill 		else  {
11221014Sbill 		    if( delta->tm_min == 0 )  {
11231014Sbill 			printf( "    " );
11241014Sbill 		    }
11251014Sbill 		    else  {
11261014Sbill 			printf( "  %1.1d ", delta->tm_min );
11271014Sbill 		    }
11281014Sbill 		}
11291014Sbill 	    }
11301014Sbill 	    else  {
11311014Sbill 		if( delta->tm_hour >= 10 )  {
11321014Sbill 		    printf( "%3.3d:", delta->tm_hour );
11331014Sbill 		}
11341014Sbill 		else  {
11351014Sbill 		    printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min );
11361014Sbill 		}
11371014Sbill 	    }
11381014Sbill 	}
11391014Sbill 	else  {
11401014Sbill 	    printf( "%3dd", delta->tm_yday );
11411014Sbill 	}
11421014Sbill }
11431014Sbill 
11441014Sbill 
11451014Sbill /*  print idle time in long format with care being taken not to pluralize
11461014Sbill  *  1 minutes or 1 hours or 1 days.
11471014Sbill  */
11481014Sbill 
11491014Sbill ltimeprint( dt )
11501014Sbill 
11511014Sbill     long	*dt;
11521014Sbill {
11531014Sbill 	struct  tm		*gmtime();
11541014Sbill 	struct  tm		*delta;
11551014Sbill 	int			printed = 1;
11561014Sbill 
11571014Sbill 	delta = gmtime( dt );
11581014Sbill 	if( delta->tm_yday == 0 )  {
11591014Sbill 	    if( delta->tm_hour == 0 )  {
11601014Sbill 		if( delta->tm_min >= 10 )  {
11611014Sbill 		    printf( "%2d minutes", delta->tm_min );
11621014Sbill 		}
11631014Sbill 		else  {
11641014Sbill 		    if( delta->tm_min == 0 )  {
11651014Sbill 			if( delta->tm_sec > 10 )  {
11661014Sbill 			    printf( "%2d seconds", delta->tm_sec );
11671014Sbill 			}
11681014Sbill 			else  {
11691014Sbill 			    printed = 0;
11701014Sbill 			}
11711014Sbill 		    }
11721014Sbill 		    else  {
11731014Sbill 			if( delta->tm_min == 1 )  {
11741014Sbill 			    if( delta->tm_sec == 1 )  {
11751014Sbill 				printf( "%1d minute %1d second",
11761014Sbill 				    delta->tm_min, delta->tm_sec );
11771014Sbill 			    }
11781014Sbill 			    else  {
11791014Sbill 				printf( "%1d minute %d seconds",
11801014Sbill 				    delta->tm_min, delta->tm_sec );
11811014Sbill 			    }
11821014Sbill 			}
11831014Sbill 			else  {
11841014Sbill 			    if( delta->tm_sec == 1 )  {
11851014Sbill 				printf( "%1d minutes %1d second",
11861014Sbill 				    delta->tm_min, delta->tm_sec );
11871014Sbill 			    }
11881014Sbill 			    else  {
11891014Sbill 				printf( "%1d minutes %d seconds",
11901014Sbill 				    delta->tm_min, delta->tm_sec );
11911014Sbill 			    }
11921014Sbill 			}
11931014Sbill 		    }
11941014Sbill 		}
11951014Sbill 	    }
11961014Sbill 	    else  {
11971014Sbill 		if( delta->tm_hour >= 10 )  {
11981014Sbill 		    printf( "%2d hours", delta->tm_hour );
11991014Sbill 		}
12001014Sbill 		else  {
12011014Sbill 		    if( delta->tm_hour == 1 )  {
12021014Sbill 			if( delta->tm_min == 1 )  {
12031014Sbill 			    printf( "%1d hour %1d minute",
12041014Sbill 				delta->tm_hour, delta->tm_min );
12051014Sbill 			}
12061014Sbill 			else  {
12071014Sbill 			    printf( "%1d hour %2d minutes",
12081014Sbill 				delta->tm_hour, delta->tm_min );
12091014Sbill 			}
12101014Sbill 		    }
12111014Sbill 		    else  {
12121014Sbill 			if( delta->tm_min == 1 )  {
12131014Sbill 			    printf( "%1d hours %1d minute",
12141014Sbill 				delta->tm_hour, delta->tm_min );
12151014Sbill 			}
12161014Sbill 			else  {
12171014Sbill 			    printf( "%1d hours %2d minutes",
12181014Sbill 				delta->tm_hour, delta->tm_min );
12191014Sbill 			}
12201014Sbill 		    }
12211014Sbill 		}
12221014Sbill 	    }
12231014Sbill 	}
12241014Sbill 	else  {
12251014Sbill 		if( delta->tm_yday >= 10 )  {
12261014Sbill 		    printf( "%2d days", delta->tm_yday );
12271014Sbill 		}
12281014Sbill 		else  {
12291014Sbill 		    if( delta->tm_yday == 1 )  {
12301014Sbill 			if( delta->tm_hour == 1 )  {
12311014Sbill 			    printf( "%1d day %1d hour",
12321014Sbill 				delta->tm_yday, delta->tm_hour );
12331014Sbill 			}
12341014Sbill 			else  {
12351014Sbill 			    printf( "%1d day %2d hours",
12361014Sbill 				delta->tm_yday, delta->tm_hour );
12371014Sbill 			}
12381014Sbill 		    }
12391014Sbill 		    else  {
12401014Sbill 			if( delta->tm_hour == 1 )  {
12411014Sbill 			    printf( "%1d days %1d hour",
12421014Sbill 				delta->tm_yday, delta->tm_hour );
12431014Sbill 			}
12441014Sbill 			else  {
12451014Sbill 			    printf( "%1d days %2d hours",
12461014Sbill 				delta->tm_yday, delta->tm_hour );
12471014Sbill 			}
12481014Sbill 		    }
12491014Sbill 		}
12501014Sbill 	}
12511014Sbill 	return( printed );
12521014Sbill }
12531014Sbill 
12541014Sbill 
12551014Sbill matchcmp( gname, login, given )
12561014Sbill 
12571014Sbill     char		*gname;
12581014Sbill     char		*login;
12591014Sbill     char		*given;
12601014Sbill {
12611014Sbill 	char		buffer[ 20 ];
12621014Sbill 	char		c;
12631014Sbill 	int		flag,  i,  unfound;
12641014Sbill 
12651014Sbill 	if( !match )  {
12661014Sbill 	    return( 0 );
12671014Sbill 	}
12681014Sbill 	else  {
12691014Sbill 	    if(  namecmp( login, given )  )  {
12701014Sbill 		return( 1 );
12711014Sbill 	    }
12729623Sshannon 	    else if (*gname == '\0')
12739623Sshannon 		return (0);
12741014Sbill 	    else  {
12751014Sbill 		if( *gname == ASTERISK )  {
12761014Sbill 		    gname++;
12771014Sbill 		}
12781014Sbill 		flag = 1;
12791014Sbill 		i = 0;
12801014Sbill 		unfound = 1;
12811014Sbill 		while(  unfound  )  {
12821014Sbill 		    if( flag )  {
12831014Sbill 			c = *gname++;
12841014Sbill 			if( c == SAMENAME )  {
12851014Sbill 			    flag = 0;
12861014Sbill 			    c = *login++;
12871014Sbill 			}
12881014Sbill 			else  {
12891014Sbill 			    unfound = (*gname != COMMA)  &&  (*gname != NULL);
12901014Sbill 			}
12911014Sbill 		    }
12921014Sbill 		    else {
12931014Sbill 			c = *login++;
12941014Sbill 			if( c == NULL )  {
12951014Sbill 			    if(  (*gname == COMMA)  ||  (*gname == NULL)  )  {
12961014Sbill 				break;
12971014Sbill 			    }
12981014Sbill 			    else  {
12991014Sbill 				flag = 1;
13001014Sbill 				continue;
13011014Sbill 			    }
13021014Sbill 			}
13031014Sbill 		    }
13041014Sbill 		    if( c == BLANK )  {
13051014Sbill 			buffer[i++] = NULL;
13061014Sbill 			if(  namecmp( buffer, given )  )  {
13071014Sbill 			    return( 1 );
13081014Sbill 			}
13091014Sbill 			i = 0;
13101014Sbill 			flag = 1;
13111014Sbill 		    }
13121014Sbill 		    else  {
13131014Sbill 			buffer[ i++ ] = c;
13141014Sbill 		    }
13151014Sbill 		}
13161014Sbill 		buffer[i++] = NULL;
13171014Sbill 		if(  namecmp( buffer, given )  )  {
13181014Sbill 		    return( 1 );
13191014Sbill 		}
13201014Sbill 		else  {
13211014Sbill 		    return( 0 );
13221014Sbill 		}
13231014Sbill 	    }
13241014Sbill 	}
13251014Sbill }
13261014Sbill 
13271014Sbill 
13281014Sbill namecmp( name1, name2 )
13291014Sbill 
13301014Sbill     char		*name1;
13311014Sbill     char		*name2;
13321014Sbill {
13331014Sbill 	char		c1,  c2;
13341014Sbill 
13351014Sbill 	c1 = *name1;
13361014Sbill 	if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) )  {
13371014Sbill 	    c1 = CAPITALIZE( c1 );
13381014Sbill 	}
13391014Sbill 	c2 = *name2;
13401014Sbill 	if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) )  {
13411014Sbill 	    c2 = CAPITALIZE( c2 );
13421014Sbill 	}
13431014Sbill 	while( c1 == c2 )  {
13441014Sbill 	    if( c1 == NULL )  {
13451014Sbill 		return( 1 );
13461014Sbill 	    }
13471014Sbill 	    c1 = *++name1;
13481014Sbill 	    if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) )  {
13491014Sbill 		c1 = CAPITALIZE( c1 );
13501014Sbill 	    }
13511014Sbill 	    c2 = *++name2;
13521014Sbill 	    if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) )  {
13531014Sbill 		c2 = CAPITALIZE( c2 );
13541014Sbill 	    }
13551014Sbill 	}
13561014Sbill 	if( *name1 == NULL )  {
13571014Sbill 	    while(  ('0' <= *name2)  &&  (*name2 <= '9')  )  {
13581014Sbill 		name2++;
13591014Sbill 	    }
13601014Sbill 	    if( *name2 == NULL )  {
13611014Sbill 		return( 1 );
13621014Sbill 	    }
13631014Sbill 	}
13641014Sbill 	else  {
13651014Sbill 	    if( *name2 == NULL )  {
13661014Sbill 		while(  ('0' <= *name1)  &&  (*name1 <= '9')  )  {
13671014Sbill 		    name1++;
13681014Sbill 		}
13691014Sbill 		if( *name1 == NULL )  {
13701014Sbill 		    return( 1 );
13711014Sbill 		}
13721014Sbill 	    }
13731014Sbill 	}
13741014Sbill 	return( 0 );
13751014Sbill }
13761014Sbill 
13771014Sbill 
13781014Sbill char  *strsave( s )
13791014Sbill 
13801014Sbill     char		*s;
13811014Sbill {
13821014Sbill 	char		*malloc();
13831014Sbill 	char		*p;
13841014Sbill 
13851014Sbill 	p = malloc( strlen( s ) + 1 );
13861014Sbill 	strcpy( p, s );
13871014Sbill }
1388*16469Ssam 
1389*16469Ssam netfinger(name)
1390*16469Ssam char *name;
1391*16469Ssam {
1392*16469Ssam 	char *host;
1393*16469Ssam 	char fname[100];
1394*16469Ssam 	struct hostent *hp;
1395*16469Ssam 	struct servent *sp;
1396*16469Ssam 	struct	sockaddr_in sin;
1397*16469Ssam 	int s;
1398*16469Ssam 	char *rindex();
1399*16469Ssam 	register FILE *f;
1400*16469Ssam 	register int c;
1401*16469Ssam 	register int lastc;
1402*16469Ssam 
1403*16469Ssam 	if (name == NULL)
1404*16469Ssam 		return(0);
1405*16469Ssam 	host = rindex(name, '@');
1406*16469Ssam 	if (host == NULL)
1407*16469Ssam 		return(0);
1408*16469Ssam 	*host++ = 0;
1409*16469Ssam 	hp = gethostbyname(host);
1410*16469Ssam 	if (hp == NULL) {
1411*16469Ssam 		static struct hostent def;
1412*16469Ssam 		static struct in_addr defaddr;
1413*16469Ssam 		static char namebuf[128];
1414*16469Ssam 		int inet_addr();
1415*16469Ssam 
1416*16469Ssam 		defaddr.s_addr = inet_addr(host);
1417*16469Ssam 		if (defaddr.s_addr == -1) {
1418*16469Ssam 			printf("unknown host: %s\n", host);
1419*16469Ssam 			return(1);
1420*16469Ssam 		}
1421*16469Ssam 		strcpy(namebuf, host);
1422*16469Ssam 		def.h_name = namebuf;
1423*16469Ssam 		def.h_addr = (char *)&defaddr;
1424*16469Ssam 		def.h_length = sizeof (struct in_addr);
1425*16469Ssam 		def.h_addrtype = AF_INET;
1426*16469Ssam 		def.h_aliases = 0;
1427*16469Ssam 		hp = &def;
1428*16469Ssam 	}
1429*16469Ssam 	printf("[%s]", hp->h_name);
1430*16469Ssam 	sp = getservbyname("finger", "tcp");
1431*16469Ssam 	if (sp == 0) {
1432*16469Ssam 		printf("tcp/finger: unknown service\n");
1433*16469Ssam 		return(1);
1434*16469Ssam 	}
1435*16469Ssam 	sin.sin_family = hp->h_addrtype;
1436*16469Ssam 	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
1437*16469Ssam 	sin.sin_port = sp->s_port;
1438*16469Ssam 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
1439*16469Ssam 	if (s < 0) {
1440*16469Ssam 		fflush(stdout);
1441*16469Ssam 		perror("socket");
1442*16469Ssam 		return(1);
1443*16469Ssam 	}
1444*16469Ssam 	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
1445*16469Ssam 		fflush(stdout);
1446*16469Ssam 		perror("connect");
1447*16469Ssam 		close(s);
1448*16469Ssam 		return(1);
1449*16469Ssam 	}
1450*16469Ssam 	printf("\n");
1451*16469Ssam 	if (large) write(s, "/W ", 3);
1452*16469Ssam 	write(s, name, strlen(name));
1453*16469Ssam 	write(s, "\r\n", 2);
1454*16469Ssam 	f = fdopen(s, "r");
1455*16469Ssam 	while ((c = getc(f)) != EOF) {
1456*16469Ssam 		switch(c) {
1457*16469Ssam 		case 0210:
1458*16469Ssam 		case 0211:
1459*16469Ssam 		case 0212:
1460*16469Ssam 		case 0214:
1461*16469Ssam 			c -= 0200;
1462*16469Ssam 			break;
1463*16469Ssam 		case 0215:
1464*16469Ssam 			c = '\n';
1465*16469Ssam 			break;
1466*16469Ssam 		}
1467*16469Ssam 		putchar(lastc = c);
1468*16469Ssam 	}
1469*16469Ssam 	if (lastc != '\n')
1470*16469Ssam 		putchar('\n');
1471*16469Ssam 	return(1);
1472*16469Ssam }
1473