use sccs
[unix-history] / usr / src / usr.bin / finger / finger.c
CommitLineData
bb95a472 1static char *sccsid = "@(#)finger.c 4.3 (Berkeley) %G%";
2e61617d
BJ
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 }
27cee9bc 602 strcpy(buf, ctime(&pers->loginat));
2e61617d
BJ
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 }
27cee9bc
KM
611 else if (pers->loginat == 0)
612 printf(" < . . . . >");
613 else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
614 printf( " <%-6.6s, %-4.4s>", buf+4, buf+20 );
615 else
616 printf(" <%-12.12s>", buf+4);
2e61617d
BJ
617 len = strlen( pers->homephone );
618 if( dialup && (len > 0) ) {
619 if( len == 8 ) {
620 printf( " " );
621 }
622 else {
623 if( len == 12 ) {
624 printf( " " );
625 }
626 else {
627 for( i = 1; i <= 21 - len; i++ ) {
628 printf( " " );
629 }
630 }
631 }
632 printf( "%s", pers->homephone );
633 }
634 else {
635 if( strlen( pers->office ) > 0 ) {
636 printf( " %-11.11s", pers->office );
637 if( strlen( pers->officephone ) > 0 ) {
638 printf( " %8.8s", pers->officephone );
639 }
640 else {
641 if( len == 8 ) {
642 printf( " %8.8s", pers->homephone );
643 }
644 }
645 }
646 else {
647 if( strlen( pers->officephone ) > 0 ) {
648 printf( " %8.8s", pers->officephone );
649 }
650 else {
651 if( len == 8 ) {
652 printf( " %8.8s", pers->homephone );
653 }
654 else {
655 if( len == 12 ) {
656 printf( " %12.12s", pers->homephone );
657 }
658 }
659 }
660 }
661 }
662 printf( "\n" );
663}
664
665
666/* print out a person in long format giving all possible information.
667 * directory and shell are inhibited if unbrief is clear.
668 */
669
670personprint( pers )
671
672 struct person *pers;
673{
674 struct passwd *pwdt = pers->pwd;
675 int idleprinted;
676
677 if( pwdt == NILPWD ) {
678 printf( "Login name: %-10s", pers->name );
679 printf( " " );
680 printf( "In real life: ???\n");
681 return;
682 }
683 printf( "Login name: %-10s", pwdt->pw_name );
684 if( pers->loggedin ) {
685 if( pers->writeable ) {
686 printf( " " );
687 }
688 else {
689 printf( " (messages off) " );
690 }
691 }
692 else {
693 printf( " " );
694 }
695 if( strlen( pers->realname ) > 0 ) {
696 printf( "In real life: %-s", pers->realname );
697 }
698 if( strlen( pers->office ) > 0 ) {
699 printf( "\nOffice: %-.11s", pers->office );
700 if( strlen( pers->officephone ) > 0 ) {
701 printf( ", %s", pers->officephone );
702 if( strlen( pers->homephone ) > 0 ) {
703 printf( " Home phone: %s", pers->homephone );
704 }
705 else {
706 if( strlen( pers->random ) > 0 ) {
707 printf( " %s", pers->random );
708 }
709 }
710 }
711 else {
712 if( strlen( pers->homephone ) > 0 ) {
713 printf(" Home phone: %s",pers->homephone);
714 }
715 if( strlen( pers->random ) > 0 ) {
716 printf( " %s", pers->random );
717 }
718 }
719 }
720 else {
721 if( strlen( pers->officephone ) > 0 ) {
722 printf( "\nPhone: %s", pers->officephone );
723 if( strlen( pers->homephone ) > 0 ) {
724 printf( "\n, %s", pers->homephone );
725 if( strlen( pers->random ) > 0 ) {
726 printf( ", %s", pers->random );
727 }
728 }
729 else {
730 if( strlen( pers->random ) > 0 ) {
731 printf( "\n, %s", pers->random );
732 }
733 }
734 }
735 else {
736 if( strlen( pers->homephone ) > 0 ) {
737 printf( "\nPhone: %s", pers->homephone );
738 if( strlen( pers->random ) > 0 ) {
739 printf( ", %s", pers->random );
740 }
741 }
742 else {
743 if( strlen( pers->random ) > 0 ) {
744 printf( "\n%s", pers->random );
745 }
746 }
747 }
748 }
749 if( unbrief ) {
750 printf( "\n" );
751 printf( "Directory: %-25s", pwdt->pw_dir );
752 if( strlen( pwdt->pw_shell ) > 0 ) {
753 printf( " Shell: %-s", pwdt->pw_shell );
754 }
755 }
756 if( pers->loggedin ) {
757 register char *ep = ctime( &pers->loginat );
758 printf("\nOn since %15.15s on %-*.*s ", &ep[4], LMAX, LMAX, pers->tty );
759 idleprinted = ltimeprint( &pers->idletime );
760 if( idleprinted ) {
761 printf( " Idle Time" );
762 }
763 }
27cee9bc
KM
764 else if (pers->loginat == 0)
765 printf("\nNever logged in.");
766 else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
767 register char *ep = ctime( &pers->loginat );
768 printf("\nLast login %10.10s, %4.4s on %.*s", ep, ep+20, LMAX, pers->tty);
769 }
2e61617d
BJ
770 else {
771 register char *ep = ctime( &pers->loginat );
772 printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty );
773 }
774 printf( "\n" );
775}
776
777
778/*
779 * very hacky section of code to format phone numbers. filled with
780 * magic constants like 4, 7 and 10.
781 */
782
783char *phone( s, len )
784
785 char *s;
786 int len;
787{
788 char *strsave();
789 char fonebuf[ 15 ];
790 int i;
791
792 switch( len ) {
793
794 case 4:
795 fonebuf[ 0 ] = ' ';
796 fonebuf[ 1 ] = 'x';
797 fonebuf[ 2 ] = '2';
798 fonebuf[ 3 ] = '-';
799 for( i = 0; i <= 3; i++ ) {
800 fonebuf[ 4 + i ] = *s++;
801 }
802 fonebuf[ 8 ] = NULL;
803 return( strsave( &fonebuf[0] ) );
804 break;
805
806 case 7:
807 for( i = 0; i <= 2; i++ ) {
808 fonebuf[ i ] = *s++;
809 }
810 fonebuf[ 3 ] = '-';
811 for( i = 0; i <= 3; i++ ) {
812 fonebuf[ 4 + i ] = *s++;
813 }
814 fonebuf[ 8 ] = NULL;
815 return( strsave( &fonebuf[0] ) );
816 break;
817
818 case 10:
819 for( i = 0; i <= 2; i++ ) {
820 fonebuf[ i ] = *s++;
821 }
822 fonebuf[ 3 ] = '-';
823 for( i = 0; i <= 2; i++ ) {
824 fonebuf[ 4 + i ] = *s++;
825 }
826 fonebuf[ 7 ] = '-';
827 for( i = 0; i <= 3; i++ ) {
828 fonebuf[ 8 + i ] = *s++;
829 }
830 fonebuf[ 12 ] = NULL;
831 return( strsave( &fonebuf[0] ) );
832 break;
833
834 default:
835 fprintf( stderr, "finger: error in phone numbering\n" );
836 return( strsave(s) );
837 break;
838 }
839}
840
841
842/* decode the information in the gecos field of /etc/passwd
843 * another hacky section of code, but given the format the stuff is in...
844 */
845
846decode( pers )
847
848 struct person *pers;
849
850{
851 struct passwd *pwdt = pers->pwd;
852 char buffer[ 40 ], *bp, *gp, *lp;
853 char *phone();
854 int alldigits;
855 int len;
856 int i;
857
858 pers->realname = NULLSTR;
859 pers->office = NULLSTR;
860 pers->officephone = NULLSTR;
861 pers->homephone = NULLSTR;
862 pers->random = NULLSTR;
863 if( pwdt != NILPWD ) {
864 gp = pwdt->pw_gecos;
865 bp = &buffer[ 0 ];
866 if( *gp == ASTERISK ) {
867 gp++;
868 }
869 while( (*gp != NULL) && (*gp != COMMA) ) { /* name */
870 if( *gp == SAMENAME ) {
871 lp = pwdt->pw_name;
872 *bp++ = CAPITALIZE(*lp++);
873 while( *lp != NULL ) {
874 *bp++ = *lp++;
875 }
876 }
877 else {
878 *bp++ = *gp;
879 }
880 gp++;
881 }
882 *bp = NULL;
883 pers->realname = malloc( strlen( &buffer[0] ) + 1 );
884 strcpy( pers->realname, &buffer[0] );
885 if( *gp++ == COMMA ) { /* office, supposedly */
886 alldigits = 1;
887 bp = &buffer[ 0 ];
888 while( (*gp != NULL) && (*gp != COMMA) ) {
889 *bp = *gp++;
890 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
891 bp++;
892 }
893 *bp = NULL;
894 len = strlen( &buffer[0] );
895 if( buffer[ len - 1 ] == CORY ) {
896 strcpy( &buffer[ len - 1 ], " Cory" );
897 pers->office = malloc( len + 5 );
898 strcpy( pers->office, &buffer[0] );
899 }
900 else {
901 if( buffer[ len - 1 ] == EVANS ) {
902 strcpy( &buffer[ len - 1 ], " Evans" );
903 pers->office = malloc( len + 6 );
904 strcpy( pers->office, &buffer[0] );
905 }
906 else {
907 if( buffer[ len - 1 ] == 'L' ) {
908 strcpy( &buffer[ len - 1 ], " LBL" );
909 pers->office = malloc( len + 4 );
910 strcpy( pers->office, &buffer[0] );
911 }
912 else {
913 if( alldigits ) {
914 if( len == 4 ) {
915 pers->officephone = phone(&buffer[0], len);
916 }
917 else {
918 if( (len == 7) || (len == 10) ) {
919 pers->homephone = phone(&buffer[0],len);
920 }
921 }
922 }
923 else {
924 pers->random = malloc( len + 1 );
925 strcpy( pers->random, &buffer[0] );
926 }
927 }
928 }
929 }
930 if( *gp++ == COMMA ) { /* office phone, theoretically */
931 bp = &buffer[ 0 ];
932 alldigits = 1;
933 while( (*gp != NULL) && (*gp != COMMA) ) {
934 *bp = *gp++;
935 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
936 bp++;
937 }
938 *bp = NULL;
939 len = strlen( &buffer[0] );
940 if( alldigits ) {
941 if( len != 4 ) {
942 if( (len == 7) || (len == 10) ) {
943 pers->homephone = phone( &buffer[0], len );
944 }
945 else {
946 pers->random = malloc( len + 1 );
947 strcpy( pers->random, &buffer[0] );
948 }
949 }
950 else {
951 pers->officephone = phone( &buffer[0], len );
952 }
953 }
954 else {
955 pers->random = malloc( len + 1 );
956 strcpy( pers->random, &buffer[0] );
957 }
958 if( *gp++ == COMMA ) { /* home phone?? */
959 bp = &buffer[ 0 ];
960 alldigits = 1;
961 while( (*gp != NULL) && (*gp != COMMA) ) {
962 *bp = *gp++;
963 alldigits = alldigits && ('0' <= *bp) &&
964 (*bp <= '9');
965 bp++;
966 }
967 *bp = NULL;
968 len = strlen( &buffer[0] );
969 if( alldigits && ( (len == 7) || (len == 10) ) ) {
970 if( *pers->homephone != NULL ) {
971 pers->officephone = pers->homephone;
972 }
973 pers->homephone = phone( &buffer[0], len );
974 }
975 else {
976 pers->random = malloc( strlen( &buffer[0] ) + 1 );
977 strcpy( pers->random, &buffer[0] );
978 }
979 }
980 }
981 }
982 if( pers->loggedin == 0 ) {
983 findwhen( pers );
984 }
985 else {
986 findidle( pers );
987 }
988 }
989}
990
991
992/* find the last log in of a user by checking the LASTLOG file.
993 * the entry is indexed by the uid, so this can only be done if
994 * the uid is known (which it isn't in quick mode)
995 */
996
997fwopen()
998{
999 if( ( lf = open(LASTLOG, 0) ) >= 0 ) {
1000 llopenerr = 0;
1001 }
1002 else {
1003 fprintf( stderr, "finger: lastlog open error\n" );
1004 llopenerr = 1;
1005 }
1006}
1007
1008
1009findwhen( pers )
1010
1011 struct person *pers;
1012{
1013 struct passwd *pwdt = pers->pwd;
1014 struct lastlog ll;
1015 int llsize = sizeof ll;
1016 int i;
1017
1018 if( !llopenerr ) {
1019 lseek( lf, pwdt->pw_uid*llsize, 0 );
27cee9bc 1020 if ((i = read( lf, (char *) &ll, llsize )) == llsize) {
2e61617d
BJ
1021 for( i = 0; i < LMAX; i++ ) {
1022 pers->tty[ i ] = ll.ll_line[ i ];
1023 }
1024 pers->tty[ LMAX ] = NULL;
1025 pers->loginat = ll.ll_time;
1026 }
1027 else {
27cee9bc
KM
1028 if (i != 0)
1029 fprintf(stderr, "finger: lastlog read error\n");
2e61617d
BJ
1030 pers->tty[ 0 ] = NULL;
1031 pers->loginat = 0L;
1032 }
1033 }
1034 else {
1035 pers->tty[ 0 ] = NULL;
1036 pers->loginat = 0L;
1037 }
1038}
1039
1040
1041fwclose()
1042{
1043 if( !llopenerr ) {
1044 close( lf );
1045 }
1046}
1047
1048
1049/* find the idle time of a user by doing a stat on /dev/histty,
1050 * where histty has been gotten from USERLOG, supposedly.
1051 */
1052
1053findidle( pers )
1054
1055 struct person *pers;
1056{
1057 struct stat ttystatus;
1058 struct passwd *pwdt = pers->pwd;
1059 char buffer[ 20 ];
1060 char *TTY = "/dev/";
1061 int TTYLEN = strlen( TTY );
1062 int i;
1063
1064 strcpy( &buffer[0], TTY );
1065 i = 0;
1066 do {
1067 buffer[ TTYLEN + i ] = pers->tty[ i ];
1068 } while( ++i <= LMAX );
1069 if( stat( &buffer[0], &ttystatus ) >= 0 ) {
1070 time( &tloc );
1071 if( tloc < ttystatus.st_atime ) {
1072 pers->idletime = 0L;
1073 }
1074 else {
1075 pers->idletime = tloc - ttystatus.st_atime;
1076 }
1077 if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) {
1078 pers->writeable = 1;
1079 }
1080 else {
1081 pers->writeable = 0;
1082 }
1083 }
1084 else {
1085 fprintf( stderr, "finger: error STATing %s\n", &buffer[0] );
1086 exit( 4 );
1087 }
1088}
1089
1090
1091/* print idle time in short format; this program always prints 4 characters;
1092 * if the idle time is zero, it prints 4 blanks.
1093 */
1094
1095stimeprint( dt )
1096
1097 long *dt;
1098{
1099 struct tm *gmtime();
1100 struct tm *delta;
1101
1102 delta = gmtime( dt );
1103 if( delta->tm_yday == 0 ) {
1104 if( delta->tm_hour == 0 ) {
1105 if( delta->tm_min >= 10 ) {
1106 printf( " %2.2d ", delta->tm_min );
1107 }
1108 else {
1109 if( delta->tm_min == 0 ) {
1110 printf( " " );
1111 }
1112 else {
1113 printf( " %1.1d ", delta->tm_min );
1114 }
1115 }
1116 }
1117 else {
1118 if( delta->tm_hour >= 10 ) {
1119 printf( "%3.3d:", delta->tm_hour );
1120 }
1121 else {
1122 printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min );
1123 }
1124 }
1125 }
1126 else {
1127 printf( "%3dd", delta->tm_yday );
1128 }
1129}
1130
1131
1132/* print idle time in long format with care being taken not to pluralize
1133 * 1 minutes or 1 hours or 1 days.
1134 */
1135
1136ltimeprint( dt )
1137
1138 long *dt;
1139{
1140 struct tm *gmtime();
1141 struct tm *delta;
1142 int printed = 1;
1143
1144 delta = gmtime( dt );
1145 if( delta->tm_yday == 0 ) {
1146 if( delta->tm_hour == 0 ) {
1147 if( delta->tm_min >= 10 ) {
1148 printf( "%2d minutes", delta->tm_min );
1149 }
1150 else {
1151 if( delta->tm_min == 0 ) {
1152 if( delta->tm_sec > 10 ) {
1153 printf( "%2d seconds", delta->tm_sec );
1154 }
1155 else {
1156 printed = 0;
1157 }
1158 }
1159 else {
1160 if( delta->tm_min == 1 ) {
1161 if( delta->tm_sec == 1 ) {
1162 printf( "%1d minute %1d second",
1163 delta->tm_min, delta->tm_sec );
1164 }
1165 else {
1166 printf( "%1d minute %d seconds",
1167 delta->tm_min, delta->tm_sec );
1168 }
1169 }
1170 else {
1171 if( delta->tm_sec == 1 ) {
1172 printf( "%1d minutes %1d second",
1173 delta->tm_min, delta->tm_sec );
1174 }
1175 else {
1176 printf( "%1d minutes %d seconds",
1177 delta->tm_min, delta->tm_sec );
1178 }
1179 }
1180 }
1181 }
1182 }
1183 else {
1184 if( delta->tm_hour >= 10 ) {
1185 printf( "%2d hours", delta->tm_hour );
1186 }
1187 else {
1188 if( delta->tm_hour == 1 ) {
1189 if( delta->tm_min == 1 ) {
1190 printf( "%1d hour %1d minute",
1191 delta->tm_hour, delta->tm_min );
1192 }
1193 else {
1194 printf( "%1d hour %2d minutes",
1195 delta->tm_hour, delta->tm_min );
1196 }
1197 }
1198 else {
1199 if( delta->tm_min == 1 ) {
1200 printf( "%1d hours %1d minute",
1201 delta->tm_hour, delta->tm_min );
1202 }
1203 else {
1204 printf( "%1d hours %2d minutes",
1205 delta->tm_hour, delta->tm_min );
1206 }
1207 }
1208 }
1209 }
1210 }
1211 else {
1212 if( delta->tm_yday >= 10 ) {
1213 printf( "%2d days", delta->tm_yday );
1214 }
1215 else {
1216 if( delta->tm_yday == 1 ) {
1217 if( delta->tm_hour == 1 ) {
1218 printf( "%1d day %1d hour",
1219 delta->tm_yday, delta->tm_hour );
1220 }
1221 else {
1222 printf( "%1d day %2d hours",
1223 delta->tm_yday, delta->tm_hour );
1224 }
1225 }
1226 else {
1227 if( delta->tm_hour == 1 ) {
1228 printf( "%1d days %1d hour",
1229 delta->tm_yday, delta->tm_hour );
1230 }
1231 else {
1232 printf( "%1d days %2d hours",
1233 delta->tm_yday, delta->tm_hour );
1234 }
1235 }
1236 }
1237 }
1238 return( printed );
1239}
1240
1241
1242matchcmp( gname, login, given )
1243
1244 char *gname;
1245 char *login;
1246 char *given;
1247{
1248 char buffer[ 20 ];
1249 char c;
1250 int flag, i, unfound;
1251
1252 if( !match ) {
1253 return( 0 );
1254 }
1255 else {
1256 if( namecmp( login, given ) ) {
1257 return( 1 );
1258 }
bb95a472
BS
1259 else if (*gname == '\0')
1260 return (0);
2e61617d
BJ
1261 else {
1262 if( *gname == ASTERISK ) {
1263 gname++;
1264 }
1265 flag = 1;
1266 i = 0;
1267 unfound = 1;
1268 while( unfound ) {
1269 if( flag ) {
1270 c = *gname++;
1271 if( c == SAMENAME ) {
1272 flag = 0;
1273 c = *login++;
1274 }
1275 else {
1276 unfound = (*gname != COMMA) && (*gname != NULL);
1277 }
1278 }
1279 else {
1280 c = *login++;
1281 if( c == NULL ) {
1282 if( (*gname == COMMA) || (*gname == NULL) ) {
1283 break;
1284 }
1285 else {
1286 flag = 1;
1287 continue;
1288 }
1289 }
1290 }
1291 if( c == BLANK ) {
1292 buffer[i++] = NULL;
1293 if( namecmp( buffer, given ) ) {
1294 return( 1 );
1295 }
1296 i = 0;
1297 flag = 1;
1298 }
1299 else {
1300 buffer[ i++ ] = c;
1301 }
1302 }
1303 buffer[i++] = NULL;
1304 if( namecmp( buffer, given ) ) {
1305 return( 1 );
1306 }
1307 else {
1308 return( 0 );
1309 }
1310 }
1311 }
1312}
1313
1314
1315namecmp( name1, name2 )
1316
1317 char *name1;
1318 char *name2;
1319{
1320 char c1, c2;
1321
1322 c1 = *name1;
1323 if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) {
1324 c1 = CAPITALIZE( c1 );
1325 }
1326 c2 = *name2;
1327 if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) {
1328 c2 = CAPITALIZE( c2 );
1329 }
1330 while( c1 == c2 ) {
1331 if( c1 == NULL ) {
1332 return( 1 );
1333 }
1334 c1 = *++name1;
1335 if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) {
1336 c1 = CAPITALIZE( c1 );
1337 }
1338 c2 = *++name2;
1339 if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) {
1340 c2 = CAPITALIZE( c2 );
1341 }
1342 }
1343 if( *name1 == NULL ) {
1344 while( ('0' <= *name2) && (*name2 <= '9') ) {
1345 name2++;
1346 }
1347 if( *name2 == NULL ) {
1348 return( 1 );
1349 }
1350 }
1351 else {
1352 if( *name2 == NULL ) {
1353 while( ('0' <= *name1) && (*name1 <= '9') ) {
1354 name1++;
1355 }
1356 if( *name1 == NULL ) {
1357 return( 1 );
1358 }
1359 }
1360 }
1361 return( 0 );
1362}
1363
1364
1365char *strsave( s )
1366
1367 char *s;
1368{
1369 char *malloc();
1370 char *p;
1371
1372 p = malloc( strlen( s ) + 1 );
1373 strcpy( p, s );
1374}