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