source: trunk/minix/commands/simple/finger.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

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