don't open pw file if only doing net finger
[unix-history] / usr / src / usr.bin / finger / finger.c
CommitLineData
22e155fc
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
840fc587 13#ifndef lint
711974ba 14static char sccsid[] = "@(#)finger.c 5.2 (Berkeley) %G%";
22e155fc 15#endif not lint
2e61617d 16
f5ebcf9e
EW
17/*
18 * This is a finger program. It prints out useful information about users
19 * by digging it up from various system files. It is not very portable
20 * because the most useful parts of the information (the full user name,
21 * office, and phone numbers) are all stored in the VAX-unused gecos field
22 * of /etc/passwd, which, unfortunately, other UNIXes use for other things.
2e61617d 23 *
f5ebcf9e
EW
24 * There are three output formats, all of which give login name, teletype
25 * line number, and login time. The short output format is reminiscent
26 * of finger on ITS, and gives one line of information per user containing
27 * in addition to the minimum basic requirements (MBR), the full name of
28 * the user, his idle time and office location and phone number. The
29 * quick style output is UNIX who-like, giving only name, teletype and
30 * login time. Finally, the long style output give the same information
31 * as the short (in more legible format), the home directory and shell
32 * of the user, and, if it exits, a copy of the file .plan in the users
33 * home directory. Finger may be called with or without a list of people
34 * to finger -- if no list is given, all the people currently logged in
35 * are fingered.
2e61617d 36 *
f5ebcf9e 37 * The program is validly called by one of the following:
2e61617d
BJ
38 *
39 * finger {short form list of users}
40 * finger -l {long form list of users}
41 * finger -b {briefer long form list of users}
42 * finger -q {quick list of users}
43 * finger -i {quick list of users with idle times}
44 * finger namelist {long format list of specified users}
45 * finger -s namelist {short format list of specified users}
46 * finger -w namelist {narrow short format list of specified users}
47 *
f5ebcf9e
EW
48 * where 'namelist' is a list of users login names.
49 * The other options can all be given after one '-', or each can have its
50 * own '-'. The -f option disables the printing of headers for short and
51 * quick outputs. The -b option briefens long format outputs. The -p
52 * option turns off plans for long format outputs.
2e61617d
BJ
53 */
54
f5ebcf9e
EW
55#include <sys/types.h>
56#include <sys/stat.h>
57#include <utmp.h>
58#include <sys/signal.h>
59#include <pwd.h>
60#include <stdio.h>
61#include <lastlog.h>
62#include <ctype.h>
63#include <sys/time.h>
64#include <sys/socket.h>
65#include <netinet/in.h>
66#include <netdb.h>
67
68#define ASTERISK '*' /* ignore this in real name */
69#define COMMA ',' /* separator in pw_gecos field */
70#define COMMAND '-' /* command line flag char */
71#define CORY 'C' /* cory hall office */
72#define EVANS 'E' /* evans hall office */
73#define SAMENAME '&' /* repeat login name in real name */
74#define TALKABLE 0222 /* tty is writable if 222 mode */
75
76struct utmp user;
77#define NMAX sizeof(user.ut_name)
78#define LMAX sizeof(user.ut_line)
79#define HMAX sizeof(user.ut_host)
80
81struct person { /* one for each person fingered */
82 char *name; /* name */
83 char tty[LMAX+1]; /* null terminated tty line */
84 char host[HMAX+1]; /* null terminated remote host name */
85 long loginat; /* time of (last) login */
86 long idletime; /* how long idle (if logged in) */
87 char *realname; /* pointer to full name */
88 char *office; /* pointer to office name */
89 char *officephone; /* pointer to office phone no. */
90 char *homephone; /* pointer to home phone no. */
91 char *random; /* for any random stuff in pw_gecos */
92 struct passwd *pwd; /* structure of /etc/passwd stuff */
93 char loggedin; /* person is logged in */
94 char writable; /* tty is writable */
95 char original; /* this is not a duplicate entry */
96 struct person *link; /* link to next person */
2e61617d
BJ
97};
98
f5ebcf9e
EW
99char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */
100char USERLOG[] = "/etc/utmp"; /* who is logged in */
101char PLAN[] = "/.plan"; /* what plan file is */
102char PROJ[] = "/.project"; /* what project file */
103
104int unbrief = 1; /* -b option default */
105int header = 1; /* -f option default */
106int hack = 1; /* -h option default */
107int idle = 0; /* -i option default */
108int large = 0; /* -l option default */
109int match = 1; /* -m option default */
110int plan = 1; /* -p option default */
111int unquick = 1; /* -q option default */
112int small = 0; /* -s option default */
113int wide = 1; /* -w option default */
114
115int unshort;
116int lf; /* LASTLOG file descriptor */
117struct person *person1; /* list of people */
118long tloc; /* current time */
119
120struct passwd *pwdcopy();
121char *strcpy();
122char *malloc();
123char *ctime();
124
125main(argc, argv)
126 int argc;
127 register char **argv;
2e61617d 128{
f5ebcf9e
EW
129 FILE *fp;
130 register char *s;
131
132 /* parse command line for (optional) arguments */
133 while (*++argv && **argv == COMMAND)
134 for (s = *argv + 1; *s; s++)
135 switch (*s) {
136 case 'b':
137 unbrief = 0;
138 break;
139 case 'f':
140 header = 0;
141 break;
142 case 'h':
143 hack = 0;
144 break;
145 case 'i':
146 idle = 1;
147 unquick = 0;
148 break;
149 case 'l':
150 large = 1;
151 break;
152 case 'm':
153 match = 0;
154 break;
155 case 'p':
156 plan = 0;
157 break;
158 case 'q':
159 unquick = 0;
160 break;
161 case 's':
162 small = 1;
163 break;
164 case 'w':
165 wide = 0;
166 break;
167 default:
168 fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
169 exit(1);
2e61617d 170 }
f5ebcf9e
EW
171 if (unquick || idle)
172 time(&tloc);
173 /*
174 * *argv == 0 means no names given
175 */
176 if (*argv == 0)
177 doall();
178 else
179 donames(argv);
711974ba
EW
180 if (person1)
181 print();
f5ebcf9e
EW
182 exit(0);
183}
2e61617d 184
f5ebcf9e
EW
185doall()
186{
187 register struct person *p;
188 register struct passwd *pw;
189 int uf;
190 char name[NMAX + 1];
191
192 unshort = large;
193 if ((uf = open(USERLOG, 0)) < 0) {
194 fprintf(stderr, "finger: error opening %s\n", USERLOG);
195 exit(2);
196 }
197 if (unquick) {
198 extern _pw_stayopen;
2e61617d 199
2e61617d 200 setpwent();
f5ebcf9e 201 _pw_stayopen = 1;
2e61617d 202 fwopen();
f5ebcf9e
EW
203 }
204 while (read(uf, (char *)&user, sizeof user) == sizeof user) {
205 if (user.ut_name[0] == 0)
206 continue;
207 if (person1 == 0)
208 p = person1 = (struct person *) malloc(sizeof *p);
209 else {
210 p->link = (struct person *) malloc(sizeof *p);
2e61617d 211 p = p->link;
2e61617d 212 }
f5ebcf9e
EW
213 bcopy(user.ut_name, name, NMAX);
214 name[NMAX] = 0;
215 bcopy(user.ut_line, p->tty, LMAX);
216 p->tty[LMAX] = 0;
217 bcopy(user.ut_host, p->host, HMAX);
218 p->host[HMAX] = 0;
219 p->loginat = user.ut_time;
220 p->pwd = 0;
221 p->loggedin = 1;
222 if (unquick && (pw = getpwnam(name))) {
223 p->pwd = pwdcopy(pw);
224 decode(p);
225 p->name = p->pwd->pw_name;
226 } else
227 p->name = strcpy(malloc(strlen(name) + 1), name);
228 }
229 if (unquick) {
2e61617d
BJ
230 fwclose();
231 endpwent();
2e61617d 232 }
f5ebcf9e
EW
233 close(uf);
234 if (person1 == 0) {
235 printf("No one logged on\n");
711974ba 236 return;
f5ebcf9e
EW
237 }
238 p->link = 0;
239}
240
241donames(argv)
242 char **argv;
243{
244 register struct person *p;
245 register struct passwd *pw;
246 int uf;
247
248 /*
249 * get names from command line and check to see if they're
250 * logged in
251 */
252 unshort = !small;
253 for (; *argv != 0; argv++) {
254 if (netfinger(*argv))
255 continue;
256 if (person1 == 0)
257 p = person1 = (struct person *) malloc(sizeof *p);
258 else {
259 p->link = (struct person *) malloc(sizeof *p);
260 p = p->link;
b474790b 261 }
f5ebcf9e 262 p->name = *argv;
2e61617d 263 p->loggedin = 0;
f5ebcf9e
EW
264 p->original = 1;
265 p->pwd = 0;
266 }
711974ba
EW
267 if (person1 == 0)
268 return;
f5ebcf9e
EW
269 p->link = 0;
270 /*
271 * if we are doing it, read /etc/passwd for the useful info
272 */
273 if (unquick) {
2e61617d 274 setpwent();
f5ebcf9e
EW
275 if (!match) {
276 extern _pw_stayopen;
277
278 _pw_stayopen = 1;
279 for (p = person1; p != 0; p = p->link)
280 if (pw = getpwnam(p->name))
281 p->pwd = pwdcopy(pw);
282 } else while ((pw = getpwent()) != 0) {
283 for (p = person1; p != 0; p = p->link) {
284 if (!p->original)
285 continue;
286 if (strcmp(p->name, pw->pw_name) != 0 &&
287 !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
288 continue;
289 if (p->pwd == 0)
290 p->pwd = pwdcopy(pw);
291 else {
292 struct person *new;
293 /*
294 * handle multiple login names, insert
295 * new "duplicate" entry behind
296 */
297 new = (struct person *)
298 malloc(sizeof *new);
299 new->pwd = pwdcopy(pw);
300 new->name = p->name;
301 new->original = 1;
302 new->loggedin = 0;
303 new->link = p->link;
304 p->original = 0;
305 p->link = new;
306 p = new;
307 }
2e61617d 308 }
2e61617d
BJ
309 }
310 endpwent();
f5ebcf9e
EW
311 }
312 /* Now get login information */
313 if ((uf = open(USERLOG, 0)) < 0) {
314 fprintf(stderr, "finger: error opening %s\n", USERLOG);
315 exit(2);
316 }
317 while (read(uf, (char *)&user, sizeof user) == sizeof user) {
318 if (*user.ut_name == 0)
319 continue;
320 for (p = person1; p != 0; p = p->link) {
321 if (p->loggedin == 2)
322 continue;
323 if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
324 user.ut_name, NMAX) != 0)
325 continue;
326 if (p->loggedin == 0) {
327 bcopy(user.ut_line, p->tty, LMAX);
328 p->tty[LMAX] = 0;
329 bcopy(user.ut_host, p->host, HMAX);
330 p->host[HMAX] = 0;
331 p->loginat = user.ut_time;
332 p->loggedin = 1;
333 } else { /* p->loggedin == 1 */
334 struct person *new;
335 new = (struct person *) malloc(sizeof *new);
336 new->name = p->name;
337 bcopy(user.ut_line, new->tty, LMAX);
338 new->tty[LMAX] = 0;
339 bcopy(user.ut_host, new->host, HMAX);
340 new->host[HMAX] = 0;
341 new->loginat = user.ut_time;
342 new->pwd = p->pwd;
343 new->loggedin = 1;
344 new->original = 0;
345 new->link = p->link;
346 p->loggedin = 2;
347 p->link = new;
348 p = new;
2e61617d 349 }
2e61617d 350 }
f5ebcf9e
EW
351 }
352 close(uf);
353 if (unquick) {
2e61617d 354 fwopen();
f5ebcf9e
EW
355 for (p = person1; p != 0; p = p->link)
356 decode(p);
2e61617d 357 fwclose();
2e61617d 358 }
f5ebcf9e 359}
2e61617d 360
f5ebcf9e
EW
361print()
362{
363 register FILE *fp;
364 register struct person *p;
365 register char *s;
366 register c;
367
368 /*
369 * print out what we got
370 */
371 if (header) {
372 if (unquick) {
373 if (!unshort)
374 if (wide)
375 printf("Login Name TTY Idle When Office\n");
376 else
377 printf("Login TTY Idle When Office\n");
378 } else {
379 printf("Login TTY When");
380 if (idle)
381 printf(" Idle");
382 putchar('\n');
2e61617d 383 }
2e61617d 384 }
f5ebcf9e
EW
385 for (p = person1; p != 0; p = p->link) {
386 if (!unquick) {
387 quickprint(p);
388 continue;
389 }
390 if (!unshort) {
391 shortprint(p);
392 continue;
393 }
394 personprint(p);
395 if (p->pwd != 0) {
396 if (hack) {
397 s = malloc(strlen(p->pwd->pw_dir) +
398 sizeof PROJ);
399 strcpy(s, p->pwd->pw_dir);
400 strcat(s, PROJ);
401 if ((fp = fopen(s, "r")) != 0) {
402 printf("Project: ");
403 while ((c = getc(fp)) != EOF) {
404 if (c == '\n')
405 break;
406 putchar(c);
407 }
408 fclose(fp);
409 putchar('\n');
2e61617d 410 }
f5ebcf9e 411 free(s);
2e61617d 412 }
f5ebcf9e
EW
413 if (plan) {
414 s = malloc(strlen(p->pwd->pw_dir) +
415 sizeof PLAN);
416 strcpy(s, p->pwd->pw_dir);
417 strcat(s, PLAN);
418 if ((fp = fopen(s, "r")) == 0)
419 printf("No Plan.\n");
420 else {
421 printf("Plan:\n");
422 while ((c = getc(fp)) != EOF)
423 putchar(c);
424 fclose(fp);
2e61617d 425 }
f5ebcf9e 426 free(s);
2e61617d 427 }
2e61617d 428 }
f5ebcf9e
EW
429 if (p->link != 0)
430 putchar('\n');
431 }
2e61617d
BJ
432}
433
f5ebcf9e
EW
434/*
435 * Duplicate a pwd entry.
436 * Note: Only the useful things (what the program currently uses) are copied.
2e61617d 437 */
f5ebcf9e
EW
438struct passwd *
439pwdcopy(pfrom)
440 register struct passwd *pfrom;
2e61617d 441{
f5ebcf9e
EW
442 register struct passwd *pto;
443
444 pto = (struct passwd *) malloc(sizeof *pto);
445#define savestr(s) strcpy(malloc(strlen(s) + 1), s)
446 pto->pw_name = savestr(pfrom->pw_name);
2e61617d 447 pto->pw_uid = pfrom->pw_uid;
f5ebcf9e
EW
448 pto->pw_gecos = savestr(pfrom->pw_gecos);
449 pto->pw_dir = savestr(pfrom->pw_dir);
450 pto->pw_shell = savestr(pfrom->pw_shell);
451#undef savestr
452 return pto;
2e61617d
BJ
453}
454
f5ebcf9e
EW
455/*
456 * print out information on quick format giving just name, tty, login time
457 * and idle time if idle is set.
2e61617d 458 */
f5ebcf9e
EW
459quickprint(pers)
460 register struct person *pers;
2e61617d 461{
f5ebcf9e
EW
462 printf("%-*.*s ", NMAX, NMAX, pers->name);
463 if (pers->loggedin) {
464 if (idle) {
465 findidle(pers);
466 printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
467 LMAX, pers->tty, ctime(&pers->loginat));
468 ltimeprint(" ", &pers->idletime, "");
469 } else
470 printf(" %-*s %-16.16s", LMAX,
471 pers->tty, ctime(&pers->loginat));
472 putchar('\n');
473 } else
474 printf(" Not Logged In\n");
2e61617d
BJ
475}
476
f5ebcf9e
EW
477/*
478 * print out information in short format, giving login name, full name,
479 * tty, idle time, login time, office location and phone.
2e61617d 480 */
f5ebcf9e
EW
481shortprint(pers)
482 register struct person *pers;
2e61617d 483{
f5ebcf9e
EW
484 char *p;
485 char dialup;
2e61617d 486
f5ebcf9e
EW
487 if (pers->pwd == 0) {
488 printf("%-15s ???\n", pers->name);
489 return;
2e61617d 490 }
f5ebcf9e 491 printf("%-*s", NMAX, pers->pwd->pw_name);
2e61617d 492 dialup = 0;
f5ebcf9e
EW
493 if (wide) {
494 if (pers->realname)
495 printf(" %-20.20s", pers->realname);
496 else
497 printf(" ??? ");
2e61617d 498 }
f5ebcf9e
EW
499 putchar(' ');
500 if (pers->loggedin && !pers->writable)
501 putchar('*');
502 else
503 putchar(' ');
504 if (*pers->tty) {
505 if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
506 pers->tty[2] == 'y') {
507 if (pers->tty[3] == 'd' && pers->loggedin)
508 dialup = 1;
509 printf("%-2.2s ", pers->tty + 3);
510 } else
511 printf("%-2.2s ", pers->tty);
512 } else
513 printf(" ");
514 p = ctime(&pers->loginat);
515 if (pers->loggedin) {
516 stimeprint(&pers->idletime);
517 printf(" %3.3s %-5.5s ", p, p + 11);
518 } else if (pers->loginat == 0)
519 printf(" < . . . . >");
27cee9bc 520 else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
f5ebcf9e 521 printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
27cee9bc 522 else
f5ebcf9e
EW
523 printf(" <%-12.12s>", p + 4);
524 if (dialup && pers->homephone)
525 printf(" %20s", pers->homephone);
526 else {
527 if (pers->office)
528 printf(" %-11.11s", pers->office);
529 else if (pers->officephone || pers->homephone)
530 printf(" ");
531 if (pers->officephone)
532 printf(" %s", pers->officephone);
533 else if (pers->homephone)
534 printf(" %s", pers->homephone);
2e61617d 535 }
f5ebcf9e 536 putchar('\n');
2e61617d
BJ
537}
538
f5ebcf9e
EW
539/*
540 * print out a person in long format giving all possible information.
541 * directory and shell are inhibited if unbrief is clear.
2e61617d 542 */
f5ebcf9e
EW
543personprint(pers)
544 register struct person *pers;
2e61617d 545{
f5ebcf9e
EW
546 if (pers->pwd == 0) {
547 printf("Login name: %-10s\t\t\tIn real life: ???\n",
548 pers->name);
549 return;
2e61617d 550 }
f5ebcf9e
EW
551 printf("Login name: %-10s", pers->pwd->pw_name);
552 if (pers->loggedin && !pers->writable)
553 printf(" (messages off) ");
554 else
555 printf(" ");
556 if (pers->realname)
557 printf("In real life: %s", pers->realname);
558 if (pers->office) {
559 printf("\nOffice: %-.11s", pers->office);
560 if (pers->officephone) {
561 printf(", %s", pers->officephone);
562 if (pers->homephone)
563 printf("\t\tHome phone: %s", pers->homephone);
564 else if (pers->random)
565 printf("\t\t%s", pers->random);
566 } else
567 if (pers->homephone)
568 printf("\t\t\tHome phone: %s", pers->homephone);
569 else if (pers->random)
570 printf("\t\t\t%s", pers->random);
571 } else if (pers->officephone) {
572 printf("\nPhone: %s", pers->officephone);
573 if (pers->homephone)
574 printf(", %s", pers->homephone);
575 if (pers->random)
576 printf(", %s", pers->random);
577 } else if (pers->homephone) {
578 printf("\nPhone: %s", pers->homephone);
579 if (pers->random)
580 printf(", %s", pers->random);
581 } else if (pers->random)
582 printf("\n%s", pers->random);
583 if (unbrief) {
584 printf("\nDirectory: %-25s", pers->pwd->pw_dir);
585 if (*pers->pwd->pw_shell)
586 printf("\tShell: %-s", pers->pwd->pw_shell);
2e61617d 587 }
f5ebcf9e
EW
588 if (pers->loggedin) {
589 register char *ep = ctime(&pers->loginat);
590 if (*pers->host) {
591 printf("\nOn since %15.15s on %s from %s",
592 &ep[4], pers->tty, pers->host);
593 ltimeprint("\n", &pers->idletime, " Idle Time");
594 } else {
595 printf("\nOn since %15.15s on %-*s",
596 &ep[4], LMAX, pers->tty);
597 ltimeprint("\t", &pers->idletime, " Idle Time");
2e61617d 598 }
f5ebcf9e
EW
599 } else if (pers->loginat == 0)
600 printf("\nNever logged in.");
27cee9bc 601 else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
f5ebcf9e
EW
602 register char *ep = ctime(&pers->loginat);
603 printf("\nLast login %10.10s, %4.4s on %s",
604 ep, ep+20, pers->tty);
605 if (*pers->host)
606 printf(" from %s", pers->host);
607 } else {
608 register char *ep = ctime(&pers->loginat);
609 printf("\nLast login %16.16s on %s", ep, pers->tty);
610 if (*pers->host)
611 printf(" from %s", pers->host);
27cee9bc 612 }
f5ebcf9e 613 putchar('\n');
2e61617d
BJ
614}
615
2e61617d
BJ
616/*
617 * very hacky section of code to format phone numbers. filled with
618 * magic constants like 4, 7 and 10.
619 */
f5ebcf9e
EW
620char *
621phone(s, len, alldigits)
622 register char *s;
623 int len;
624 char alldigits;
2e61617d 625{
f5ebcf9e
EW
626 char fonebuf[15];
627 register char *p = fonebuf;
628 register i;
629
630 if (!alldigits)
631 return (strcpy(malloc(len + 1), s));
632 switch (len) {
633 case 4:
634 *p++ = ' ';
635 *p++ = 'x';
636 *p++ = '2';
637 *p++ = '-';
638 for (i = 0; i < 4; i++)
639 *p++ = *s++;
2e61617d 640 break;
f5ebcf9e
EW
641 case 7:
642 for (i = 0; i < 3; i++)
643 *p++ = *s++;
644 *p++ = '-';
645 for (i = 0; i < 4; i++)
646 *p++ = *s++;
2e61617d 647 break;
f5ebcf9e
EW
648 case 10:
649 for (i = 0; i < 3; i++)
650 *p++ = *s++;
651 *p++ = '-';
652 for (i = 0; i < 3; i++)
653 *p++ = *s++;
654 *p++ = '-';
655 for (i = 0; i < 4; i++)
656 *p++ = *s++;
2e61617d 657 break;
f5ebcf9e
EW
658 case 0:
659 return 0;
660 default:
661 return (strcpy(malloc(len + 1), s));
2e61617d 662 }
f5ebcf9e
EW
663 *p++ = 0;
664 return (strcpy(malloc(p - fonebuf), fonebuf));
2e61617d
BJ
665}
666
f5ebcf9e
EW
667/*
668 * decode the information in the gecos field of /etc/passwd
2e61617d 669 */
f5ebcf9e
EW
670decode(pers)
671 register struct person *pers;
2e61617d 672{
f5ebcf9e
EW
673 char buffer[256];
674 register char *bp, *gp, *lp;
675 int alldigits;
676 int hasspace;
677 int len;
678
679 pers->realname = 0;
680 pers->office = 0;
681 pers->officephone = 0;
682 pers->homephone = 0;
683 pers->random = 0;
684 if (pers->pwd == 0)
685 return;
686 gp = pers->pwd->pw_gecos;
687 bp = buffer;
688 if (*gp == ASTERISK)
2e61617d 689 gp++;
f5ebcf9e
EW
690 while (*gp && *gp != COMMA) /* name */
691 if (*gp == SAMENAME) {
692 lp = pers->pwd->pw_name;
693 if (islower(*lp))
694 *bp++ = toupper(*lp++);
695 while (*bp++ = *lp++)
696 ;
697 bp--;
698 gp++;
699 } else
700 *bp++ = *gp++;
701 *bp++ = 0;
702 if ((len = bp - buffer) > 1)
703 pers->realname = strcpy(malloc(len), buffer);
704 if (*gp == COMMA) { /* office */
705 gp++;
706 hasspace = 0;
707 bp = buffer;
708 while (*gp && *gp != COMMA) {
709 *bp = *gp++;
710 if (*bp == ' ')
711 hasspace = 1;
712 /* leave 5 for Cory and Evans expansion */
713 if (bp < buffer + sizeof buffer - 6)
714 bp++;
2e61617d 715 }
f5ebcf9e
EW
716 *bp = 0;
717 len = bp - buffer;
718 bp--; /* point to last character */
719 if (hasspace || len == 0)
720 len++;
721 else if (*bp == CORY) {
722 strcpy(bp, " Cory");
723 len += 5;
724 } else if (*bp == EVANS) {
725 strcpy(bp, " Evans");
726 len += 6;
727 } else
728 len++;
729 if (len > 1)
730 pers->office = strcpy(malloc(len), buffer);
731 }
732 if (*gp == COMMA) { /* office phone */
2e61617d 733 gp++;
f5ebcf9e 734 bp = buffer;
2e61617d 735 alldigits = 1;
f5ebcf9e
EW
736 while (*gp && *gp != COMMA) {
737 *bp = *gp++;
738 if (!isdigit(*bp))
739 alldigits = 0;
740 if (bp < buffer + sizeof buffer - 1)
741 bp++;
2e61617d 742 }
f5ebcf9e
EW
743 *bp = 0;
744 pers->officephone = phone(buffer, bp - buffer, alldigits);
745 }
746 if (*gp == COMMA) { /* home phone */
747 gp++;
748 bp = buffer;
749 alldigits = 1;
750 while (*gp && *gp != COMMA) {
2e61617d 751 *bp = *gp++;
f5ebcf9e
EW
752 if (!isdigit(*bp))
753 alldigits = 0;
754 if (bp < buffer + sizeof buffer - 1)
2e61617d 755 bp++;
2e61617d 756 }
f5ebcf9e
EW
757 *bp = 0;
758 pers->homephone = phone(buffer, bp - buffer, alldigits);
2e61617d 759 }
f5ebcf9e
EW
760 if (pers->loggedin)
761 findidle(pers);
762 else
763 findwhen(pers);
2e61617d
BJ
764}
765
f5ebcf9e
EW
766/*
767 * find the last log in of a user by checking the LASTLOG file.
768 * the entry is indexed by the uid, so this can only be done if
769 * the uid is known (which it isn't in quick mode)
2e61617d
BJ
770 */
771
772fwopen()
773{
f5ebcf9e
EW
774 if ((lf = open(LASTLOG, 0)) < 0)
775 fprintf(stderr, "finger: %s open error\n", LASTLOG);
2e61617d
BJ
776}
777
f5ebcf9e
EW
778findwhen(pers)
779 register struct person *pers;
2e61617d 780{
f5ebcf9e
EW
781 struct lastlog ll;
782 int i;
783
784 if (lf >= 0) {
785 lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
786 if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
787 bcopy(ll.ll_line, pers->tty, LMAX);
788 pers->tty[LMAX] = 0;
789 bcopy(ll.ll_host, pers->host, HMAX);
790 pers->host[HMAX] = 0;
791 pers->loginat = ll.ll_time;
792 } else {
793 if (i != 0)
794 fprintf(stderr, "finger: %s read error\n",
795 LASTLOG);
796 pers->tty[0] = 0;
797 pers->host[0] = 0;
798 pers->loginat = 0L;
799 }
800 } else {
801 pers->tty[0] = 0;
802 pers->host[0] = 0;
2e61617d 803 pers->loginat = 0L;
2e61617d
BJ
804 }
805}
806
2e61617d
BJ
807fwclose()
808{
f5ebcf9e
EW
809 if (lf >= 0)
810 close(lf);
2e61617d
BJ
811}
812
f5ebcf9e
EW
813/*
814 * find the idle time of a user by doing a stat on /dev/tty??,
815 * where tty?? has been gotten from USERLOG, supposedly.
2e61617d 816 */
f5ebcf9e
EW
817findidle(pers)
818 register struct person *pers;
2e61617d 819{
f5ebcf9e
EW
820 struct stat ttystatus;
821 static char buffer[20] = "/dev/";
822 long t;
823#define TTYLEN 5
824
825 strcpy(buffer + TTYLEN, pers->tty);
826 buffer[TTYLEN+LMAX] = 0;
827 if (stat(buffer, &ttystatus) < 0) {
828 fprintf(stderr, "finger: Can't stat %s\n", buffer);
829 exit(4);
2e61617d 830 }
f5ebcf9e
EW
831 time(&t);
832 if (t < ttystatus.st_atime)
833 pers->idletime = 0L;
834 else
835 pers->idletime = t - ttystatus.st_atime;
836 pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
2e61617d
BJ
837}
838
f5ebcf9e
EW
839/*
840 * print idle time in short format; this program always prints 4 characters;
841 * if the idle time is zero, it prints 4 blanks.
2e61617d 842 */
f5ebcf9e
EW
843stimeprint(dt)
844 long *dt;
2e61617d 845{
f5ebcf9e
EW
846 register struct tm *delta;
847
848 delta = gmtime(dt);
849 if (delta->tm_yday == 0)
850 if (delta->tm_hour == 0)
851 if (delta->tm_min == 0)
852 printf(" ");
853 else
854 printf(" %2d", delta->tm_min);
855 else
856 if (delta->tm_hour >= 10)
857 printf("%3d:", delta->tm_hour);
858 else
859 printf("%1d:%02d",
860 delta->tm_hour, delta->tm_min);
861 else
862 printf("%3dd", delta->tm_yday);
2e61617d
BJ
863}
864
f5ebcf9e
EW
865/*
866 * print idle time in long format with care being taken not to pluralize
867 * 1 minutes or 1 hours or 1 days.
868 * print "prefix" first.
2e61617d 869 */
f5ebcf9e
EW
870ltimeprint(before, dt, after)
871 long *dt;
872 char *before, *after;
2e61617d 873{
f5ebcf9e 874 register struct tm *delta;
2e61617d 875
f5ebcf9e
EW
876 delta = gmtime(dt);
877 if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
878 delta->tm_sec <= 10)
879 return (0);
880 printf("%s", before);
881 if (delta->tm_yday >= 10)
882 printf("%d days", delta->tm_yday);
883 else if (delta->tm_yday > 0)
884 printf("%d day%s %d hour%s",
885 delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
886 delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
887 else
888 if (delta->tm_hour >= 10)
889 printf("%d hours", delta->tm_hour);
890 else if (delta->tm_hour > 0)
891 printf("%d hour%s %d minute%s",
892 delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
893 delta->tm_min, delta->tm_min == 1 ? "" : "s");
894 else
895 if (delta->tm_min >= 10)
896 printf("%2d minutes", delta->tm_min);
897 else if (delta->tm_min == 0)
898 printf("%2d seconds", delta->tm_sec);
899 else
900 printf("%d minute%s %d second%s",
901 delta->tm_min,
902 delta->tm_min == 1 ? "" : "s",
903 delta->tm_sec,
904 delta->tm_sec == 1 ? "" : "s");
905 printf("%s", after);
2e61617d
BJ
906}
907
f5ebcf9e
EW
908matchcmp(gname, login, given)
909 register char *gname;
910 char *login;
911 char *given;
2e61617d 912{
f5ebcf9e
EW
913 char buffer[100];
914 register char *bp, *lp;
915 register c;
916
917 if (*gname == ASTERISK)
918 gname++;
919 lp = 0;
920 bp = buffer;
921 for (;;)
922 switch (c = *gname++) {
923 case SAMENAME:
924 for (lp = login; bp < buffer + sizeof buffer
925 && (*bp++ = *lp++);)
926 ;
927 bp--;
928 break;
929 case ' ':
930 case COMMA:
931 case '\0':
932 *bp = 0;
933 if (namecmp(buffer, given))
934 return (1);
935 if (c == COMMA || c == 0)
936 return (0);
937 bp = buffer;
938 break;
939 default:
940 if (bp < buffer + sizeof buffer)
941 *bp++ = c;
2e61617d 942 }
f5ebcf9e 943 /*NOTREACHED*/
2e61617d
BJ
944}
945
f5ebcf9e
EW
946namecmp(name1, name2)
947 register char *name1, *name2;
2e61617d 948{
f5ebcf9e
EW
949 register c1, c2;
950
951 for (;;) {
952 c1 = *name1++;
953 if (islower(c1))
954 c1 = toupper(c1);
955 c2 = *name2++;
956 if (islower(c2))
957 c2 = toupper(c2);
958 if (c1 != c2)
959 break;
960 if (c1 == 0)
961 return (1);
2e61617d 962 }
f5ebcf9e
EW
963 if (!c1) {
964 for (name2--; isdigit(*name2); name2++)
965 ;
966 if (*name2 == 0)
967 return (1);
968 } else if (!c2) {
969 for (name1--; isdigit(*name1); name1++)
970 ;
971 if (*name2 == 0)
972 return (1);
2e61617d 973 }
f5ebcf9e 974 return (0);
2e61617d 975}
b474790b
SL
976
977netfinger(name)
f5ebcf9e 978 char *name;
b474790b
SL
979{
980 char *host;
981 char fname[100];
982 struct hostent *hp;
983 struct servent *sp;
f5ebcf9e 984 struct sockaddr_in sin;
b474790b
SL
985 int s;
986 char *rindex();
987 register FILE *f;
988 register int c;
989 register int lastc;
990
991 if (name == NULL)
f5ebcf9e 992 return (0);
b474790b
SL
993 host = rindex(name, '@');
994 if (host == NULL)
f5ebcf9e 995 return (0);
b474790b
SL
996 *host++ = 0;
997 hp = gethostbyname(host);
998 if (hp == NULL) {
999 static struct hostent def;
1000 static struct in_addr defaddr;
1001 static char namebuf[128];
1002 int inet_addr();
1003
1004 defaddr.s_addr = inet_addr(host);
1005 if (defaddr.s_addr == -1) {
1006 printf("unknown host: %s\n", host);
f5ebcf9e 1007 return (1);
b474790b
SL
1008 }
1009 strcpy(namebuf, host);
1010 def.h_name = namebuf;
1011 def.h_addr = (char *)&defaddr;
1012 def.h_length = sizeof (struct in_addr);
1013 def.h_addrtype = AF_INET;
1014 def.h_aliases = 0;
1015 hp = &def;
1016 }
1017 printf("[%s]", hp->h_name);
1018 sp = getservbyname("finger", "tcp");
1019 if (sp == 0) {
1020 printf("tcp/finger: unknown service\n");
f5ebcf9e 1021 return (1);
b474790b
SL
1022 }
1023 sin.sin_family = hp->h_addrtype;
1024 bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
1025 sin.sin_port = sp->s_port;
1026 s = socket(hp->h_addrtype, SOCK_STREAM, 0);
1027 if (s < 0) {
1028 fflush(stdout);
1029 perror("socket");
f5ebcf9e 1030 return (1);
b474790b
SL
1031 }
1032 if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
1033 fflush(stdout);
1034 perror("connect");
1035 close(s);
f5ebcf9e 1036 return (1);
b474790b
SL
1037 }
1038 printf("\n");
1039 if (large) write(s, "/W ", 3);
1040 write(s, name, strlen(name));
1041 write(s, "\r\n", 2);
1042 f = fdopen(s, "r");
1043 while ((c = getc(f)) != EOF) {
1044 switch(c) {
1045 case 0210:
1046 case 0211:
1047 case 0212:
1048 case 0214:
1049 c -= 0200;
1050 break;
1051 case 0215:
1052 c = '\n';
1053 break;
1054 }
1055 putchar(lastc = c);
1056 }
1057 if (lastc != '\n')
1058 putchar('\n');
f5ebcf9e 1059 return (1);
b474790b 1060}