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