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