lprint.c revision 9994
197952Sdougb/*
297952Sdougb * Copyright (c) 1989, 1993
397952Sdougb *	The Regents of the University of California.  All rights reserved.
497952Sdougb *
597952Sdougb * This code is derived from software contributed to Berkeley by
697952Sdougb * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
797952Sdougb *
897952Sdougb * Redistribution and use in source and binary forms, with or without
997952Sdougb * modification, are permitted provided that the following conditions
1097952Sdougb * are met:
1197952Sdougb * 1. Redistributions of source code must retain the above copyright
1297952Sdougb *    notice, this list of conditions and the following disclaimer.
1397952Sdougb * 2. Redistributions in binary form must reproduce the above copyright
1497952Sdougb *    notice, this list of conditions and the following disclaimer in the
1597952Sdougb *    documentation and/or other materials provided with the distribution.
1697952Sdougb * 3. All advertising materials mentioning features or use of this software
1797952Sdougb *    must display the following acknowledgement:
1897952Sdougb *	This product includes software developed by the University of
1997952Sdougb *	California, Berkeley and its contributors.
2097952Sdougb * 4. Neither the name of the University nor the names of its contributors
2197952Sdougb *    may be used to endorse or promote products derived from this software
2297952Sdougb *    without specific prior written permission.
2397952Sdougb *
2497952Sdougb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2597952Sdougb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2697952Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2797952Sdougb * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2897952Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2997952Sdougb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30114924Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31101773Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3297952Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33218535Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34216343Sdougb * SUCH DAMAGE.
3597952Sdougb */
36101773Sdougb
3797952Sdougb#ifndef lint
38101773Sdougbstatic char sccsid[] = "@(#)lprint.c	8.1 (Berkeley) 6/6/93";
39101773Sdougb#endif /* not lint */
40120836Sdougb
41120836Sdougb#include <sys/types.h>
42120836Sdougb#include <sys/stat.h>
43120836Sdougb#include <sys/time.h>
44120836Sdougb#include <fcntl.h>
45120836Sdougb#include <time.h>
46120836Sdougb#include <db.h>
47120836Sdougb#include <pwd.h>
48120836Sdougb#include <utmp.h>
49120836Sdougb#include <errno.h>
50188498Sed#include <unistd.h>
51101897Sdougb#include <stdio.h>
5297952Sdougb#include <ctype.h>
53101773Sdougb#include <string.h>
54101773Sdougb#include <paths.h>
5597952Sdougb#include "finger.h"
56216196Sdougb
57101773Sdougb#define	LINE_LEN	80
58101897Sdougb#define	TAB_LEN		8		/* 8 spaces between tabs */
59188498Sed#define	_PATH_FORWARD	".forward"
60101773Sdougb#define	_PATH_PLAN	".plan"
6197952Sdougb#define	_PATH_PROJECT	".project"
6297952Sdougb
63101773Sdougbstatic int	demi_print __P((char *, int));
64101773Sdougbstatic void	lprint __P((PERSON *));
65101773Sdougbstatic int	show_text __P((char *, char *, char *));
6697952Sdougbstatic void	vputc __P((int));
67120836Sdougb
68120836Sdougbvoid
69120836Sdougblflag_print()
70120836Sdougb{
71120836Sdougb	extern int pplan;
72120836Sdougb	register PERSON *pn;
73120836Sdougb	register int sflag, r;
74120836Sdougb	DBT data, key;
75120836Sdougb
76120836Sdougb	for (sflag = R_FIRST;; sflag = R_NEXT) {
77120836Sdougb		r = (*db->seq)(db, &key, &data, sflag);
78120836Sdougb		if (r == -1)
79120836Sdougb			err("db seq: %s", strerror(errno));
80120836Sdougb		if (r == 1)
81120836Sdougb			break;
82120836Sdougb		pn = *(PERSON **)data.data;
83120836Sdougb		if (sflag != R_FIRST)
84120836Sdougb			putchar('\n');
85120836Sdougb		lprint(pn);
86120836Sdougb		if (!pplan) {
87120836Sdougb			(void)show_text(pn->dir,
88120836Sdougb			    _PATH_FORWARD, "Mail forwarded to");
89120836Sdougb			(void)show_text(pn->dir, _PATH_PROJECT, "Project");
90120836Sdougb			if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
91120836Sdougb				(void)printf("No Plan.\n");
92120836Sdougb		}
9397952Sdougb	}
94120836Sdougb}
95120836Sdougb
96120836Sdougbstatic void
97120836Sdougblprint(pn)
9897952Sdougb	register PERSON *pn;
9997952Sdougb{
10097952Sdougb	extern time_t now;
10197952Sdougb	register struct tm *delta;
10297952Sdougb	register WHERE *w;
103120836Sdougb	register int cpr, len, maxlen;
104120836Sdougb	struct tm *tp;
10597952Sdougb	int oddfield;
10697952Sdougb	char *tzn;
10797952Sdougb	char t[80];
108188481Smaxim
10997952Sdougb	/*
11097952Sdougb	 * long format --
11197952Sdougb	 *	login name
11297952Sdougb	 *	real name
11397952Sdougb	 *	home directory
11497952Sdougb	 *	shell
11597952Sdougb	 *	office, office phone, home phone if available
11697952Sdougb	 *	mail status
11797952Sdougb	 */
11897952Sdougb	(void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
11997952Sdougb	    pn->name, pn->realname, pn->dir);
12097952Sdougb	(void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
12197952Sdougb
12297952Sdougb	/*
12397952Sdougb	 * try and print office, office phone, and home phone on one line;
12497952Sdougb	 * if that fails, do line filling so it looks nice.
12597952Sdougb	 */
12697952Sdougb#define	OFFICE_TAG		"Office"
12797952Sdougb#define	OFFICE_PHONE_TAG	"Office Phone"
12897952Sdougb	oddfield = 0;
12997952Sdougb	if (pn->office && pn->officephone &&
13097952Sdougb	    strlen(pn->office) + strlen(pn->officephone) +
13197952Sdougb	    sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
13297952Sdougb		(void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s",
13397952Sdougb		    OFFICE_TAG, pn->office, prphone(pn->officephone));
13497952Sdougb		oddfield = demi_print(tbuf, oddfield);
13597952Sdougb	} else {
13697952Sdougb		if (pn->office) {
13797952Sdougb			(void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
13897952Sdougb			    OFFICE_TAG, pn->office);
13997952Sdougb			oddfield = demi_print(tbuf, oddfield);
14097952Sdougb		}
14197952Sdougb		if (pn->officephone) {
14297952Sdougb			(void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
14397952Sdougb			    OFFICE_PHONE_TAG, prphone(pn->officephone));
14497952Sdougb			oddfield = demi_print(tbuf, oddfield);
14597952Sdougb		}
146101773Sdougb	}
147101773Sdougb	if (pn->homephone) {
148101773Sdougb		(void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone",
149101773Sdougb		    prphone(pn->homephone));
150101773Sdougb		oddfield = demi_print(tbuf, oddfield);
151101773Sdougb	}
152101773Sdougb	if (oddfield)
15397952Sdougb		putchar('\n');
15497952Sdougb
15597952Sdougb	/*
15697952Sdougb	 * long format con't:
157216203Sdougb	 * if logged in
15897952Sdougb	 *	terminal
15997952Sdougb	 *	idle time
16097952Sdougb	 *	if messages allowed
16197952Sdougb	 *	where logged in from
16297952Sdougb	 * if not logged in
16397952Sdougb	 *	when last logged in
16497952Sdougb	 */
16597952Sdougb	/* find out longest device name for this user for formatting */
16697952Sdougb	for (w = pn->whead, maxlen = -1; w != NULL; w = w->next)
16797952Sdougb		if ((len = strlen(w->tty)) > maxlen)
168114924Sdougb			maxlen = len;
16997952Sdougb	/* find rest of entries for user */
17097952Sdougb	for (w = pn->whead; w != NULL; w = w->next) {
17197952Sdougb		switch (w->info) {
17297952Sdougb		case LOGGEDIN:
17397952Sdougb			tp = localtime(&w->loginat);
17497952Sdougb			strftime(t, sizeof(t), "%c", tp);
17597952Sdougb			tzn = tp->tm_zone;
17697952Sdougb			cpr = printf("On since %.16s (%s) on %s",
17797952Sdougb			    t, tzn, w->tty);
17897952Sdougb			/*
179101773Sdougb			 * idle time is tough; if have one, print a comma,
18097952Sdougb			 * then spaces to pad out the device name, then the
181216206Sdougb			 * idle time.  Follow with a comma if a remote login.
18297952Sdougb			 */
18397952Sdougb			delta = gmtime(&w->idletime);
18497952Sdougb			if (delta->tm_yday || delta->tm_hour || delta->tm_min) {
18597952Sdougb				cpr += printf("%-*s idle ",
18697952Sdougb				    maxlen - strlen(w->tty) + 1, ",");
18797952Sdougb				if (delta->tm_yday > 0) {
188207153Sjilles					cpr += printf("%d day%s ",
189207153Sjilles					   delta->tm_yday,
190207153Sjilles					   delta->tm_yday == 1 ? "" : "s");
19197952Sdougb				}
192241737Sed				cpr += printf("%d:%02d",
193241737Sed				    delta->tm_hour, delta->tm_min);
19497952Sdougb				if (*w->host) {
195101773Sdougb					putchar(',');
19697952Sdougb					++cpr;
197101773Sdougb				}
198101773Sdougb			}
19997952Sdougb			if (!w->writable)
20097952Sdougb				cpr += printf(" (messages off)");
20197952Sdougb			break;
20297952Sdougb		case LASTLOG:
20397952Sdougb			if (w->loginat == 0) {
20497952Sdougb				(void)printf("Never logged in.");
205101773Sdougb				break;
206101773Sdougb			}
207216205Sdougb			tp = localtime(&w->loginat);
208188498Sed			strftime(t, sizeof(t), "%c", tp);
209188498Sed			tzn = tp->tm_zone;
21097952Sdougb			if (now - w->loginat > 86400 * 365 / 2)
211101773Sdougb				cpr =
21297952Sdougb				    printf("Last login %.16s %.4s (%s) on %s",
21397952Sdougb				    t, t + 20, tzn, w->tty);
21497952Sdougb			else
21597952Sdougb				cpr = printf("Last login %.16s (%s) on %s",
216101773Sdougb				    t, tzn, w->tty);
217101773Sdougb			break;
21897952Sdougb		}
21997952Sdougb		if (*w->host) {
22097952Sdougb			if (LINE_LEN < (cpr + 6 + strlen(w->host)))
221101773Sdougb				(void)printf("\n   ");
222101773Sdougb			(void)printf(" from %s", w->host);
223216203Sdougb		}
224216203Sdougb		putchar('\n');
225101773Sdougb	}
226101773Sdougb	if (pn->mailrecv == -1)
227101773Sdougb		printf("No Mail.\n");
228101773Sdougb	else if (pn->mailrecv > pn->mailread) {
229101773Sdougb		tp = localtime(&pn->mailrecv);
230216343Sdougb		strftime(t, sizeof(t), "%c", tp);
231216343Sdougb		tzn = tp->tm_zone;
232101773Sdougb		printf("New mail received %.16s %.4s (%s)\n", t, t + 20, tzn);
233101773Sdougb		tp = localtime(&pn->mailread);
234101773Sdougb		strftime(t, sizeof(t), "%c", tp);
23597952Sdougb		tzn = tp->tm_zone;
23697952Sdougb		printf("     Unread since %.16s %.4s (%s)\n", t, t + 20, tzn);
23797952Sdougb	} else {
23897952Sdougb		tp = localtime(&pn->mailread);
23997952Sdougb		strftime(t, sizeof(t), "%c", tp);
24097952Sdougb		tzn = tp->tm_zone;
24197952Sdougb		printf("Mail last read %.16s %.4s (%s)\n", t, t + 20, tzn);
24297952Sdougb	}
24397952Sdougb}
24497952Sdougb
245101773Sdougbstatic int
246101773Sdougbdemi_print(str, oddfield)
247101773Sdougb	char *str;
24897952Sdougb	int oddfield;
249216203Sdougb{
250216203Sdougb	static int lenlast;
251216203Sdougb	int lenthis, maxlen;
252216203Sdougb
25397952Sdougb	lenthis = strlen(str);
25497952Sdougb	if (oddfield) {
25597952Sdougb		/*
25697952Sdougb		 * We left off on an odd number of fields.  If we haven't
25797952Sdougb		 * crossed the midpoint of the screen, and we have room for
25897952Sdougb		 * the next field, print it on the same line; otherwise,
25997952Sdougb		 * print it on a new line.
26097952Sdougb		 *
26197952Sdougb		 * Note: we insist on having the right hand fields start
26297952Sdougb		 * no less than 5 tabs out.
26397952Sdougb		 */
26497952Sdougb		maxlen = 5 * TAB_LEN;
26597952Sdougb		if (maxlen < lenlast)
26697952Sdougb			maxlen = lenlast;
26797952Sdougb		if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
268101773Sdougb		    lenthis) <= LINE_LEN) {
26997952Sdougb			while(lenlast < (4 * TAB_LEN)) {
27097952Sdougb				putchar('\t');
27197952Sdougb				lenlast += TAB_LEN;
27297952Sdougb			}
27397952Sdougb			(void)printf("\t%s\n", str);	/* force one tab */
27497952Sdougb		} else {
27597952Sdougb			(void)printf("\n%s", str);	/* go to next line */
27697952Sdougb			oddfield = !oddfield;	/* this'll be undone below */
27797952Sdougb		}
27897952Sdougb	} else
27997952Sdougb		(void)printf("%s", str);
28097952Sdougb	oddfield = !oddfield;			/* toggle odd/even marker */
28197952Sdougb	lenlast = lenthis;
28297952Sdougb	return(oddfield);
28397952Sdougb}
28497952Sdougb
28597952Sdougbstatic int
28697952Sdougbshow_text(directory, file_name, header)
28797952Sdougb	char *directory, *file_name, *header;
28897952Sdougb{
28997952Sdougb	struct stat sb;
29097952Sdougb	register FILE *fp;
29197952Sdougb	register int ch, cnt, lastc;
29297952Sdougb	register char *p;
29397952Sdougb	int fd, nr;
29497952Sdougb
29597952Sdougb	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
29697952Sdougb	if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
29797952Sdougb	    sb.st_size == 0)
29897952Sdougb		return(0);
29997952Sdougb
30097952Sdougb	/* If short enough, and no newlines, show it on a single line.*/
30197952Sdougb	if (sb.st_size <= LINE_LEN - strlen(header) - 5) {
30297952Sdougb		nr = read(fd, tbuf, sizeof(tbuf));
30397952Sdougb		if (nr <= 0) {
30497952Sdougb			(void)close(fd);
30597952Sdougb			return(0);
306101773Sdougb		}
30797952Sdougb		for (p = tbuf, cnt = nr; cnt--; ++p)
30897952Sdougb			if (*p == '\n')
30997952Sdougb				break;
31097952Sdougb		if (cnt <= 1) {
31197952Sdougb			(void)printf("%s: ", header);
31297952Sdougb			for (p = tbuf, cnt = nr; cnt--; ++p)
31397952Sdougb				vputc(lastc = *p);
31497952Sdougb			if (lastc != '\n')
315188498Sed				(void)putchar('\n');
316188498Sed			(void)close(fd);
317188498Sed			return(1);
318188498Sed		}
319188498Sed		else
320188498Sed			(void)lseek(fd, 0L, SEEK_SET);
32197952Sdougb	}
322188498Sed	if ((fp = fdopen(fd, "r")) == NULL)
323188498Sed		return(0);
324216196Sdougb	(void)printf("%s:\n", header);
325216196Sdougb	while ((ch = getc(fp)) != EOF)
326216196Sdougb		vputc(lastc = ch);
327216196Sdougb	if (lastc != '\n')
328216196Sdougb		(void)putchar('\n');
329216196Sdougb	(void)fclose(fp);
330216196Sdougb	return(1);
331216196Sdougb}
332216196Sdougb
333216196Sdougbstatic void
334216196Sdougbvputc(ch)
335188498Sed	register int ch;
336188498Sed{
337188498Sed	int meta;
33897952Sdougb
33997952Sdougb	if (!isprint(ch) && !isascii(ch)) {
34097952Sdougb		(void)putchar('M');
341101773Sdougb		(void)putchar('-');
342101773Sdougb		ch = toascii(ch);
343188498Sed		meta = 1;
34497952Sdougb	} else
34597952Sdougb		meta = 0;
346216206Sdougb	if (isprint(ch) || !meta && (ch == ' ' || ch == '\t' || ch == '\n'))
34797952Sdougb		(void)putchar(ch);
34897952Sdougb	else {
34997952Sdougb		(void)putchar('^');
35097952Sdougb		(void)putchar(ch == '\177' ? '?' : ch | 0100);
35197952Sdougb	}
35297952Sdougb}
353101773Sdougb