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