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