1: #ifndef lint
2: static char *sccsid = "@(#)finger.c 4.1 (Berkeley) 10/1/80";
3: #endif
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>
49: #include <lastlog.h>
50: #include <time.h>
51:
52: struct 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:
68: struct 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 loggedin; /* flag for being logged in */
74: short 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:
84: struct passwd *NILPWD = 0;
85: struct person *NILPERS = 0;
86:
87: int persize = sizeof( struct person );
88: int pwdsize = sizeof( struct passwd );
89:
90: char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */
91: char USERLOG[] = "/etc/utmp"; /* who is logged in */
92: char outbuf[BUFSIZ]; /* output buffer */
93: char *ctime();
94:
95: int unbrief = 1; /* -b option default */
96: int = 1; /* -f option default */
97: int hack = 1; /* -h option default */
98: int idle = 0; /* -i option default */
99: int large = 0; /* -l option default */
100: int match = 1; /* -m option default */
101: int plan = 1; /* -p option default */
102: int unquick = 1; /* -q option default */
103: int small = 0; /* -s option default */
104: int wide = 1; /* -w option default */
105:
106: int lf;
107: int llopenerr;
108:
109: long tloc; /* current time */
110:
111:
112:
113: main( 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;
126: int 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:
494: pwdcopy( 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:
514: quickprint( pers )
515:
516: struct person *pers;
517: {
518: printf( "%-*.*s", NMAX, NMAX, pers->name );
519: printf( " " );
520: if( pers->loggedin ) {
521: if( idle ) {
522: findidle( pers );
523: if( pers->writeable ) {
524: printf( " %-*.*s %-16.16s", LMAX, LMAX,
525: pers->tty, ctime( &pers->loginat ) );
526: }
527: else {
528: printf( "*%-*.*s %-16.16s", LMAX, LMAX,
529: pers->tty, ctime( &pers->loginat ) );
530: }
531: printf( " " );
532: }
533: else {
534: printf( " %-*.*s %-16.16s", LMAX, LMAX,
535: pers->tty, ctime( &pers->loginat ) );
536: }
537: }
538: else {
539: printf( " Not Logged In" );
540: }
541: printf( "\n" );
542: }
543:
544:
545: /* print out information in short format, giving login name, full name,
546: * tty, idle time, login time, office location and phone.
547: */
548:
549: shortprint( pers )
550:
551: struct person *pers;
552:
553: {
554: struct passwd *pwdt = pers->pwd;
555: char buf[ 26 ];
556: int i, len, offset, dialup;
557:
558: if( pwdt == NILPWD ) {
559: printf( "%-*.*s", NMAX, NMAX, pers->name );
560: printf( " ???\n" );
561: return;
562: }
563: printf( "%-*.*s", NMAX, NMAX, pwdt->pw_name );
564: dialup = 0;
565: if( wide ) {
566: if( strlen( pers->realname ) > 0 ) {
567: printf( " %-20.20s", pers->realname );
568: }
569: else {
570: printf( " ??? " );
571: }
572: }
573: if( pers->loggedin ) {
574: if( pers->writeable ) {
575: printf( " " );
576: }
577: else {
578: printf( " *" );
579: }
580: }
581: else {
582: printf( " " );
583: }
584: if( strlen( pers->tty ) > 0 ) {
585: strcpy( buf, pers->tty );
586: if( (buf[0] == 't') && (buf[1] == 't') && (buf[2] == 'y') ) {
587: offset = 3;
588: for( i = 0; i < 2; i++ ) {
589: buf[i] = buf[i + offset];
590: }
591: }
592: if( (buf[0] == 'd') && pers->loggedin ) {
593: dialup = 1;
594: }
595: printf( "%-2.2s ", buf );
596: }
597: else {
598: printf( " " );
599: }
600: strcpy( buf, ctime( &pers->loginat ) );
601: if( pers->loggedin ) {
602: stimeprint( &pers->idletime );
603: offset = 7;
604: for( i = 4; i < 19; i++ ) {
605: buf[i] = buf[i + offset];
606: }
607: printf( " %-9.9s ", buf );
608: }
609: else {
610: printf( " " );
611: offset = 4;
612: for( i = 0; i <22; i++ ) {
613: buf[i] = buf[i + offset];
614: }
615: printf( "<%-12.12s>", buf );
616: }
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:
670: personprint( 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: }
764: else {
765: register char *ep = ctime( &pers->loginat );
766: printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty );
767: }
768: printf( "\n" );
769: }
770:
771:
772: /*
773: * very hacky section of code to format phone numbers. filled with
774: * magic constants like 4, 7 and 10.
775: */
776:
777: char *
778: phone( s, len )
779:
780: char *s;
781: int len;
782: {
783: char *strsave();
784: char fonebuf[ 15 ];
785: int i;
786:
787: switch( len ) {
788:
789: case 4:
790: fonebuf[ 0 ] = ' ';
791: fonebuf[ 1 ] = 'x';
792: fonebuf[ 2 ] = '2';
793: fonebuf[ 3 ] = '-';
794: for( i = 0; i <= 3; i++ ) {
795: fonebuf[ 4 + i ] = *s++;
796: }
797: fonebuf[ 8 ] = NULL;
798: return( strsave( &fonebuf[0] ) );
799: /*NOTREACHED*/
800:
801: case 7:
802: for( i = 0; i <= 2; i++ ) {
803: fonebuf[ i ] = *s++;
804: }
805: fonebuf[ 3 ] = '-';
806: for( i = 0; i <= 3; i++ ) {
807: fonebuf[ 4 + i ] = *s++;
808: }
809: fonebuf[ 8 ] = NULL;
810: return( strsave( &fonebuf[0] ) );
811: break;
812:
813: case 10:
814: for( i = 0; i <= 2; i++ ) {
815: fonebuf[ i ] = *s++;
816: }
817: fonebuf[ 3 ] = '-';
818: for( i = 0; i <= 2; i++ ) {
819: fonebuf[ 4 + i ] = *s++;
820: }
821: fonebuf[ 7 ] = '-';
822: for( i = 0; i <= 3; i++ ) {
823: fonebuf[ 8 + i ] = *s++;
824: }
825: fonebuf[ 12 ] = NULL;
826: return( strsave( &fonebuf[0] ) );
827: /*NOTREACHED*/
828:
829: default:
830: fprintf( stderr, "finger: error in phone numbering\n" );
831: return( strsave(s) );
832: /*NOTREACHED*/
833: }
834: /*NOTREACHED*/
835: }
836:
837:
838: /* decode the information in the gecos field of /etc/passwd
839: * another hacky section of code, but given the format the stuff is in...
840: */
841:
842: decode( pers )
843:
844: struct person *pers;
845:
846: {
847: struct passwd *pwdt = pers->pwd;
848: char buffer[ 40 ], *bp, *gp, *lp;
849: char *phone();
850: int alldigits;
851: int len;
852:
853: pers->realname = NULLSTR;
854: pers->office = NULLSTR;
855: pers->officephone = NULLSTR;
856: pers->homephone = NULLSTR;
857: pers->random = NULLSTR;
858: if( pwdt != NILPWD ) {
859: gp = pwdt->pw_gecos;
860: bp = &buffer[ 0 ];
861: if( *gp == ASTERISK ) {
862: gp++;
863: }
864: while( (*gp != NULL) && (*gp != COMMA) ) { /* name */
865: if( *gp == SAMENAME ) {
866: lp = pwdt->pw_name;
867: *bp++ = CAPITALIZE(*lp++);
868: while( *lp != NULL ) {
869: *bp++ = *lp++;
870: }
871: }
872: else {
873: *bp++ = *gp;
874: }
875: gp++;
876: }
877: *bp = NULL;
878: pers->realname = malloc( strlen( &buffer[0] ) + 1 );
879: strcpy( pers->realname, &buffer[0] );
880: if( *gp++ == COMMA ) { /* office, supposedly */
881: alldigits = 1;
882: bp = &buffer[ 0 ];
883: while( (*gp != NULL) && (*gp != COMMA) ) {
884: *bp = *gp++;
885: alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
886: bp++;
887: }
888: *bp = NULL;
889: len = strlen( &buffer[0] );
890: if( buffer[ len - 1 ] == CORY ) {
891: strcpy( &buffer[ len - 1 ], " Cory" );
892: pers->office = malloc( len + 5 );
893: strcpy( pers->office, &buffer[0] );
894: }
895: else {
896: if( buffer[ len - 1 ] == EVANS ) {
897: strcpy( &buffer[ len - 1 ], " Evans" );
898: pers->office = malloc( len + 6 );
899: strcpy( pers->office, &buffer[0] );
900: }
901: else {
902: if( buffer[ len - 1 ] == 'L' ) {
903: strcpy( &buffer[ len - 1 ], " LBL" );
904: pers->office = malloc( len + 4 );
905: strcpy( pers->office, &buffer[0] );
906: }
907: else {
908: if( alldigits ) {
909: if( len == 4 ) {
910: pers->officephone = phone(&buffer[0], len);
911: }
912: else {
913: if( (len == 7) || (len == 10) ) {
914: pers->homephone = phone(&buffer[0],len);
915: }
916: }
917: }
918: else {
919: pers->random = malloc( len + 1 );
920: strcpy( pers->random, &buffer[0] );
921: }
922: }
923: }
924: }
925: if( *gp++ == COMMA ) { /* office phone, theoretically */
926: bp = &buffer[ 0 ];
927: alldigits = 1;
928: while( (*gp != NULL) && (*gp != COMMA) ) {
929: *bp = *gp++;
930: alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
931: bp++;
932: }
933: *bp = NULL;
934: len = strlen( &buffer[0] );
935: if( alldigits ) {
936: if( len != 4 ) {
937: if( (len == 7) || (len == 10) ) {
938: pers->homephone = phone( &buffer[0], len );
939: }
940: else {
941: pers->random = malloc( len + 1 );
942: strcpy( pers->random, &buffer[0] );
943: }
944: }
945: else {
946: pers->officephone = phone( &buffer[0], len );
947: }
948: }
949: else {
950: pers->random = malloc( len + 1 );
951: strcpy( pers->random, &buffer[0] );
952: }
953: if( *gp++ == COMMA ) { /* home phone?? */
954: bp = &buffer[ 0 ];
955: alldigits = 1;
956: while( (*gp != NULL) && (*gp != COMMA) ) {
957: *bp = *gp++;
958: alldigits = alldigits && ('0' <= *bp) &&
959: (*bp <= '9');
960: bp++;
961: }
962: *bp = NULL;
963: len = strlen( &buffer[0] );
964: if( alldigits && ( (len == 7) || (len == 10) ) ) {
965: if( *pers->homephone != NULL ) {
966: pers->officephone = pers->homephone;
967: }
968: pers->homephone = phone( &buffer[0], len );
969: }
970: else {
971: pers->random = malloc( strlen( &buffer[0] ) + 1 );
972: strcpy( pers->random, &buffer[0] );
973: }
974: }
975: }
976: }
977: if( pers->loggedin == 0 ) {
978: findwhen( pers );
979: }
980: else {
981: findidle( pers );
982: }
983: }
984: }
985:
986:
987: /* find the last log in of a user by checking the LASTLOG file.
988: * the entry is indexed by the uid, so this can only be done if
989: * the uid is known (which it isn't in quick mode)
990: */
991:
992: fwopen()
993: {
994: if( ( lf = open(LASTLOG, 0) ) >= 0 ) {
995: llopenerr = 0;
996: }
997: else {
998: #ifdef notdef
999: /* lots of places don't have lastlog, so don't complain */
1000: fprintf( stderr, "finger: lastlog open error\n" );
1001: #endif
1002: llopenerr = 1;
1003: }
1004: }
1005:
1006:
1007: findwhen( pers )
1008:
1009: struct person *pers;
1010: {
1011: struct passwd *pwdt = pers->pwd;
1012: struct lastlog ll;
1013: int llsize = sizeof ll;
1014: int i;
1015:
1016: if( !llopenerr ) {
1017: lseek( lf, (long) pwdt->pw_uid*llsize, 0 );
1018: if( read( lf, (char *) &ll, llsize ) == llsize ) {
1019: for( i = 0; i < LMAX; i++ ) {
1020: pers->tty[ i ] = ll.ll_line[ i ];
1021: }
1022: pers->tty[ LMAX ] = NULL;
1023: pers->loginat = ll.ll_time;
1024: }
1025: else {
1026: fprintf( stderr, "finger: lastlog read error\n" );
1027: pers->tty[ 0 ] = NULL;
1028: pers->loginat = 0L;
1029: }
1030: }
1031: else {
1032: pers->tty[ 0 ] = NULL;
1033: pers->loginat = 0L;
1034: }
1035: }
1036:
1037:
1038: fwclose()
1039: {
1040: if( !llopenerr ) {
1041: close( lf );
1042: }
1043: }
1044:
1045:
1046: /* find the idle time of a user by doing a stat on /dev/histty,
1047: * where histty has been gotten from USERLOG, supposedly.
1048: */
1049:
1050: findidle( pers )
1051:
1052: struct person *pers;
1053: {
1054: struct stat ttystatus;
1055: char buffer[ 20 ];
1056: char *TTY = "/dev/";
1057: int TTYLEN = strlen( TTY );
1058: int i;
1059:
1060: strcpy( &buffer[0], TTY );
1061: i = 0;
1062: do {
1063: buffer[ TTYLEN + i ] = pers->tty[ i ];
1064: } while( ++i <= LMAX );
1065: if( stat( &buffer[0], &ttystatus ) >= 0 ) {
1066: time( &tloc );
1067: if( tloc < ttystatus.st_atime ) {
1068: pers->idletime = 0L;
1069: }
1070: else {
1071: pers->idletime = tloc - ttystatus.st_atime;
1072: }
1073: if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) {
1074: pers->writeable = 1;
1075: }
1076: else {
1077: pers->writeable = 0;
1078: }
1079: }
1080: else {
1081: fprintf( stderr, "finger: error STATing %s\n", &buffer[0] );
1082: exit( 4 );
1083: }
1084: }
1085:
1086:
1087: /* print idle time in short format; this program always prints 4 characters;
1088: * if the idle time is zero, it prints 4 blanks.
1089: */
1090:
1091: stimeprint( dt )
1092:
1093: long *dt;
1094: {
1095: struct tm *gmtime();
1096: struct tm *delta;
1097:
1098: delta = gmtime( dt );
1099: if( delta->tm_yday == 0 ) {
1100: if( delta->tm_hour == 0 ) {
1101: if( delta->tm_min >= 10 ) {
1102: printf( " %2.2d ", delta->tm_min );
1103: }
1104: else {
1105: if( delta->tm_min == 0 ) {
1106: printf( " " );
1107: }
1108: else {
1109: printf( " %1.1d ", delta->tm_min );
1110: }
1111: }
1112: }
1113: else {
1114: if( delta->tm_hour >= 10 ) {
1115: printf( "%3.3d:", delta->tm_hour );
1116: }
1117: else {
1118: printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min );
1119: }
1120: }
1121: }
1122: else {
1123: printf( "%3dd", delta->tm_yday );
1124: }
1125: }
1126:
1127:
1128: /* print idle time in long format with care being taken not to pluralize
1129: * 1 minutes or 1 hours or 1 days.
1130: */
1131:
1132: ltimeprint( dt )
1133:
1134: long *dt;
1135: {
1136: struct tm *gmtime();
1137: struct tm *delta;
1138: int printed = 1;
1139:
1140: delta = gmtime( dt );
1141: if( delta->tm_yday == 0 ) {
1142: if( delta->tm_hour == 0 ) {
1143: if( delta->tm_min >= 10 ) {
1144: printf( "%2d minutes", delta->tm_min );
1145: }
1146: else {
1147: if( delta->tm_min == 0 ) {
1148: if( delta->tm_sec > 10 ) {
1149: printf( "%2d seconds", delta->tm_sec );
1150: }
1151: else {
1152: printed = 0;
1153: }
1154: }
1155: else {
1156: if( delta->tm_min == 1 ) {
1157: if( delta->tm_sec == 1 ) {
1158: printf( "%1d minute %1d second",
1159: delta->tm_min, delta->tm_sec );
1160: }
1161: else {
1162: printf( "%1d minute %d seconds",
1163: delta->tm_min, delta->tm_sec );
1164: }
1165: }
1166: else {
1167: if( delta->tm_sec == 1 ) {
1168: printf( "%1d minutes %1d second",
1169: delta->tm_min, delta->tm_sec );
1170: }
1171: else {
1172: printf( "%1d minutes %d seconds",
1173: delta->tm_min, delta->tm_sec );
1174: }
1175: }
1176: }
1177: }
1178: }
1179: else {
1180: if( delta->tm_hour >= 10 ) {
1181: printf( "%2d hours", delta->tm_hour );
1182: }
1183: else {
1184: if( delta->tm_hour == 1 ) {
1185: if( delta->tm_min == 1 ) {
1186: printf( "%1d hour %1d minute",
1187: delta->tm_hour, delta->tm_min );
1188: }
1189: else {
1190: printf( "%1d hour %2d minutes",
1191: delta->tm_hour, delta->tm_min );
1192: }
1193: }
1194: else {
1195: if( delta->tm_min == 1 ) {
1196: printf( "%1d hours %1d minute",
1197: delta->tm_hour, delta->tm_min );
1198: }
1199: else {
1200: printf( "%1d hours %2d minutes",
1201: delta->tm_hour, delta->tm_min );
1202: }
1203: }
1204: }
1205: }
1206: }
1207: else {
1208: if( delta->tm_yday >= 10 ) {
1209: printf( "%2d days", delta->tm_yday );
1210: }
1211: else {
1212: if( delta->tm_yday == 1 ) {
1213: if( delta->tm_hour == 1 ) {
1214: printf( "%1d day %1d hour",
1215: delta->tm_yday, delta->tm_hour );
1216: }
1217: else {
1218: printf( "%1d day %2d hours",
1219: delta->tm_yday, delta->tm_hour );
1220: }
1221: }
1222: else {
1223: if( delta->tm_hour == 1 ) {
1224: printf( "%1d days %1d hour",
1225: delta->tm_yday, delta->tm_hour );
1226: }
1227: else {
1228: printf( "%1d days %2d hours",
1229: delta->tm_yday, delta->tm_hour );
1230: }
1231: }
1232: }
1233: }
1234: return( printed );
1235: }
1236:
1237:
1238: matchcmp( gname, login, given )
1239:
1240: char *gname;
1241: char *login;
1242: char *given;
1243: {
1244: char buffer[ 20 ];
1245: char c;
1246: int flag, i, unfound;
1247:
1248: if( !match ) {
1249: return( 0 );
1250: }
1251: else {
1252: if( namecmp( login, given ) ) {
1253: return( 1 );
1254: }
1255: else {
1256: if( *gname == ASTERISK ) {
1257: gname++;
1258: }
1259: flag = 1;
1260: i = 0;
1261: unfound = 1;
1262: while( unfound ) {
1263: if( flag ) {
1264: c = *gname++;
1265: if( c == SAMENAME ) {
1266: flag = 0;
1267: c = *login++;
1268: }
1269: else {
1270: unfound = (*gname != COMMA) && (*gname != NULL);
1271: }
1272: }
1273: else {
1274: c = *login++;
1275: if( c == NULL ) {
1276: if( (*gname == COMMA) || (*gname == NULL) ) {
1277: break;
1278: }
1279: else {
1280: flag = 1;
1281: continue;
1282: }
1283: }
1284: }
1285: if( c == BLANK ) {
1286: buffer[i++] = NULL;
1287: if( namecmp( buffer, given ) ) {
1288: return( 1 );
1289: }
1290: i = 0;
1291: flag = 1;
1292: }
1293: else {
1294: buffer[ i++ ] = c;
1295: }
1296: }
1297: buffer[i++] = NULL;
1298: if( namecmp( buffer, given ) ) {
1299: return( 1 );
1300: }
1301: else {
1302: return( 0 );
1303: }
1304: }
1305: }
1306: }
1307:
1308:
1309: namecmp( name1, name2 )
1310:
1311: char *name1;
1312: char *name2;
1313: {
1314: char c1, c2;
1315:
1316: c1 = *name1;
1317: if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) {
1318: c1 = CAPITALIZE( c1 );
1319: }
1320: c2 = *name2;
1321: if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) {
1322: c2 = CAPITALIZE( c2 );
1323: }
1324: while( c1 == c2 ) {
1325: if( c1 == NULL ) {
1326: return( 1 );
1327: }
1328: c1 = *++name1;
1329: if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) {
1330: c1 = CAPITALIZE( c1 );
1331: }
1332: c2 = *++name2;
1333: if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) {
1334: c2 = CAPITALIZE( c2 );
1335: }
1336: }
1337: if( *name1 == NULL ) {
1338: while( ('0' <= *name2) && (*name2 <= '9') ) {
1339: name2++;
1340: }
1341: if( *name2 == NULL ) {
1342: return( 1 );
1343: }
1344: }
1345: else {
1346: if( *name2 == NULL ) {
1347: while( ('0' <= *name1) && (*name1 <= '9') ) {
1348: name1++;
1349: }
1350: if( *name1 == NULL ) {
1351: return( 1 );
1352: }
1353: }
1354: }
1355: return( 0 );
1356: }
1357:
1358:
1359: char *
1360: strsave( s )
1361:
1362: char *s;
1363: {
1364: char *malloc();
1365: char *p;
1366:
1367: p = malloc( strlen( s ) + 1 );
1368: strcpy( p, s );
1369: return( p );
1370: }