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