Commit | Line | Data |
---|---|---|
6b8910b8 KB |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
f15db449 | 5 | * %sccs.include.redist.c% |
6b8910b8 KB |
6 | */ |
7 | ||
8 | #ifndef lint | |
e41644be | 9 | static char sccsid[] = "@(#)lprint.c 5.17 (Berkeley) %G%"; |
6b8910b8 KB |
10 | #endif /* not lint */ |
11 | ||
12 | #include <sys/types.h> | |
6b8910b8 KB |
13 | #include <sys/stat.h> |
14 | #include <sys/time.h> | |
516a0fd6 KB |
15 | #include <fcntl.h> |
16 | #include <time.h> | |
6b8910b8 | 17 | #include <tzfile.h> |
e48ef2de | 18 | #include <db.h> |
516a0fd6 KB |
19 | #include <pwd.h> |
20 | #include <utmp.h> | |
e48ef2de | 21 | #include <errno.h> |
516a0fd6 | 22 | #include <unistd.h> |
6b8910b8 | 23 | #include <stdio.h> |
d65ceee1 | 24 | #include <ctype.h> |
516a0fd6 | 25 | #include <string.h> |
8f2938db | 26 | #include <paths.h> |
6b8910b8 | 27 | #include "finger.h" |
6b8910b8 KB |
28 | |
29 | #define LINE_LEN 80 | |
30 | #define TAB_LEN 8 /* 8 spaces between tabs */ | |
4a5ea84d | 31 | #define _PATH_FORWARD ".forward" |
6b8910b8 KB |
32 | #define _PATH_PLAN ".plan" |
33 | #define _PATH_PROJECT ".project" | |
34 | ||
516a0fd6 KB |
35 | static int demi_print __P((char *, int)); |
36 | static void lprint __P((PERSON *)); | |
37 | static int show_text __P((char *, char *, char *)); | |
38 | static void vputc __P((int)); | |
39 | ||
40 | void | |
6b8910b8 KB |
41 | lflag_print() |
42 | { | |
6b8910b8 KB |
43 | extern int pplan; |
44 | register PERSON *pn; | |
e48ef2de KB |
45 | register int sflag, r; |
46 | DBT data, key; | |
6b8910b8 | 47 | |
e48ef2de KB |
48 | for (sflag = R_FIRST;; sflag = R_NEXT) { |
49 | r = (*db->seq)(db, &key, &data, sflag); | |
50 | if (r == -1) | |
51 | err("db seq: %s", strerror(errno)); | |
52 | if (r == 1) | |
53 | break; | |
54 | pn = *(PERSON **)data.data; | |
55 | if (sflag != R_FIRST) | |
56 | putchar('\n'); | |
6b8910b8 KB |
57 | lprint(pn); |
58 | if (!pplan) { | |
4a5ea84d KB |
59 | (void)show_text(pn->dir, |
60 | _PATH_FORWARD, "Mail forwarded to"); | |
61 | (void)show_text(pn->dir, _PATH_PROJECT, "Project"); | |
62 | if (!show_text(pn->dir, _PATH_PLAN, "Plan")) | |
6b8910b8 KB |
63 | (void)printf("No Plan.\n"); |
64 | } | |
6b8910b8 KB |
65 | } |
66 | } | |
67 | ||
516a0fd6 | 68 | static void |
6b8910b8 KB |
69 | lprint(pn) |
70 | register PERSON *pn; | |
71 | { | |
72 | extern time_t now; | |
73 | register struct tm *delta; | |
7619ff47 | 74 | register WHERE *w; |
6b8910b8 | 75 | register int cpr, len, maxlen; |
f9b6496c | 76 | struct tm *tp; |
6b8910b8 | 77 | int oddfield; |
516a0fd6 | 78 | char *t, *tzn; |
6b8910b8 KB |
79 | |
80 | /* | |
81 | * long format -- | |
82 | * login name | |
83 | * real name | |
84 | * home directory | |
85 | * shell | |
86 | * office, office phone, home phone if available | |
87 | */ | |
88 | (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", | |
89 | pn->name, pn->realname, pn->dir); | |
90 | (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); | |
91 | ||
92 | /* | |
93 | * try and print office, office phone, and home phone on one line; | |
94 | * if that fails, do line filling so it looks nice. | |
95 | */ | |
96 | #define OFFICE_TAG "Office" | |
97 | #define OFFICE_PHONE_TAG "Office Phone" | |
98 | oddfield = 0; | |
99 | if (pn->office && pn->officephone && | |
100 | strlen(pn->office) + strlen(pn->officephone) + | |
101 | sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { | |
4a5ea84d KB |
102 | (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s", |
103 | OFFICE_TAG, pn->office, prphone(pn->officephone)); | |
6b8910b8 KB |
104 | oddfield = demi_print(tbuf, oddfield); |
105 | } else { | |
106 | if (pn->office) { | |
4a5ea84d KB |
107 | (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", |
108 | OFFICE_TAG, pn->office); | |
6b8910b8 KB |
109 | oddfield = demi_print(tbuf, oddfield); |
110 | } | |
111 | if (pn->officephone) { | |
4a5ea84d KB |
112 | (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", |
113 | OFFICE_PHONE_TAG, prphone(pn->officephone)); | |
6b8910b8 KB |
114 | oddfield = demi_print(tbuf, oddfield); |
115 | } | |
116 | } | |
117 | if (pn->homephone) { | |
4a5ea84d | 118 | (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone", |
f156ea40 | 119 | prphone(pn->homephone)); |
6b8910b8 KB |
120 | oddfield = demi_print(tbuf, oddfield); |
121 | } | |
122 | if (oddfield) | |
123 | putchar('\n'); | |
124 | ||
125 | /* | |
7619ff47 | 126 | * long format con't: * if logged in |
6b8910b8 KB |
127 | * terminal |
128 | * idle time | |
129 | * if messages allowed | |
130 | * where logged in from | |
7619ff47 EW |
131 | * if not logged in |
132 | * when last logged in | |
6b8910b8 | 133 | */ |
7619ff47 | 134 | /* find out longest device name for this user for formatting */ |
3dc87a1e | 135 | for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) |
7619ff47 EW |
136 | if ((len = strlen(w->tty)) > maxlen) |
137 | maxlen = len; | |
138 | /* find rest of entries for user */ | |
139 | for (w = pn->whead; w != NULL; w = w->next) { | |
140 | switch (w->info) { | |
141 | case LOGGEDIN: | |
f9b6496c KB |
142 | tp = localtime(&w->loginat); |
143 | t = asctime(tp); | |
144 | tzn = tp->tm_zone; | |
1e75eb2b | 145 | cpr = printf("On since %.16s (%s) on %s", |
f9b6496c | 146 | t, tzn, w->tty); |
6b8910b8 KB |
147 | /* |
148 | * idle time is tough; if have one, print a comma, | |
149 | * then spaces to pad out the device name, then the | |
150 | * idle time. Follow with a comma if a remote login. | |
151 | */ | |
7619ff47 | 152 | delta = gmtime(&w->idletime); |
6b8910b8 KB |
153 | if (delta->tm_yday || delta->tm_hour || delta->tm_min) { |
154 | cpr += printf("%-*s idle ", | |
7619ff47 | 155 | maxlen - strlen(w->tty) + 1, ","); |
6b8910b8 KB |
156 | if (delta->tm_yday > 0) { |
157 | cpr += printf("%d day%s ", | |
158 | delta->tm_yday, | |
159 | delta->tm_yday == 1 ? "" : "s"); | |
160 | } | |
161 | cpr += printf("%d:%02d", | |
162 | delta->tm_hour, delta->tm_min); | |
7619ff47 | 163 | if (*w->host) { |
6b8910b8 KB |
164 | putchar(','); |
165 | ++cpr; | |
166 | } | |
167 | } | |
7619ff47 | 168 | if (!w->writable) |
6b8910b8 | 169 | cpr += printf(" (messages off)"); |
7619ff47 EW |
170 | break; |
171 | case LASTLOG: | |
172 | if (w->loginat == 0) { | |
173 | (void)printf("Never logged in."); | |
174 | break; | |
6b8910b8 | 175 | } |
f9b6496c KB |
176 | tp = localtime(&w->loginat); |
177 | t = asctime(tp); | |
178 | tzn = tp->tm_zone; | |
7619ff47 | 179 | if (now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2) |
1e75eb2b KB |
180 | cpr = |
181 | printf("Last login %.16s %.4s (%s) on %s", | |
f9b6496c | 182 | t, t + 20, tzn, w->tty); |
7619ff47 | 183 | else |
1e75eb2b | 184 | cpr = printf("Last login %.16s (%s) on %s", |
f9b6496c | 185 | t, tzn, w->tty); |
7619ff47 | 186 | break; |
6b8910b8 | 187 | } |
7619ff47 EW |
188 | if (*w->host) { |
189 | if (LINE_LEN < (cpr + 6 + strlen(w->host))) | |
6b8910b8 | 190 | (void)printf("\n "); |
7619ff47 | 191 | (void)printf(" from %s", w->host); |
6b8910b8 KB |
192 | } |
193 | putchar('\n'); | |
194 | } | |
6b8910b8 KB |
195 | } |
196 | ||
516a0fd6 | 197 | static int |
6b8910b8 KB |
198 | demi_print(str, oddfield) |
199 | char *str; | |
200 | int oddfield; | |
201 | { | |
202 | static int lenlast; | |
203 | int lenthis, maxlen; | |
204 | ||
205 | lenthis = strlen(str); | |
206 | if (oddfield) { | |
207 | /* | |
208 | * We left off on an odd number of fields. If we haven't | |
209 | * crossed the midpoint of the screen, and we have room for | |
210 | * the next field, print it on the same line; otherwise, | |
211 | * print it on a new line. | |
212 | * | |
213 | * Note: we insist on having the right hand fields start | |
214 | * no less than 5 tabs out. | |
215 | */ | |
216 | maxlen = 5 * TAB_LEN; | |
217 | if (maxlen < lenlast) | |
218 | maxlen = lenlast; | |
219 | if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + | |
220 | lenthis) <= LINE_LEN) { | |
221 | while(lenlast < (4 * TAB_LEN)) { | |
222 | putchar('\t'); | |
223 | lenlast += TAB_LEN; | |
224 | } | |
225 | (void)printf("\t%s\n", str); /* force one tab */ | |
226 | } else { | |
227 | (void)printf("\n%s", str); /* go to next line */ | |
228 | oddfield = !oddfield; /* this'll be undone below */ | |
229 | } | |
230 | } else | |
231 | (void)printf("%s", str); | |
232 | oddfield = !oddfield; /* toggle odd/even marker */ | |
233 | lenlast = lenthis; | |
234 | return(oddfield); | |
235 | } | |
236 | ||
e41644be | 237 | static int |
6b8910b8 KB |
238 | show_text(directory, file_name, header) |
239 | char *directory, *file_name, *header; | |
240 | { | |
4a5ea84d | 241 | struct stat sb; |
980f4f50 | 242 | register FILE *fp; |
4a5ea84d KB |
243 | register int ch, cnt, lastc; |
244 | register char *p; | |
245 | int fd, nr; | |
6b8910b8 | 246 | |
4a5ea84d KB |
247 | (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); |
248 | if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || | |
249 | sb.st_size == 0) | |
6b8910b8 | 250 | return(0); |
4a5ea84d KB |
251 | |
252 | /* If short enough, and no newlines, show it on a single line.*/ | |
253 | if (sb.st_size <= LINE_LEN - strlen(header) - 5) { | |
254 | nr = read(fd, tbuf, sizeof(tbuf)); | |
255 | if (nr <= 0) { | |
256 | (void)close(fd); | |
257 | return(0); | |
258 | } | |
259 | for (p = tbuf, cnt = nr; cnt--; ++p) | |
260 | if (*p == '\n') | |
261 | break; | |
262 | if (cnt <= 1) { | |
263 | (void)printf("%s: ", header); | |
264 | for (p = tbuf, cnt = nr; cnt--; ++p) | |
265 | vputc(lastc = *p); | |
266 | if (lastc != '\n') | |
267 | (void)putchar('\n'); | |
268 | (void)close(fd); | |
269 | return(1); | |
270 | } | |
271 | else | |
272 | (void)lseek(fd, 0L, SEEK_SET); | |
273 | } | |
274 | if ((fp = fdopen(fd, "r")) == NULL) | |
275 | return(0); | |
276 | (void)printf("%s:\n", header); | |
980f4f50 EW |
277 | while ((ch = getc(fp)) != EOF) |
278 | vputc(lastc = ch); | |
279 | if (lastc != '\n') | |
d65ceee1 | 280 | (void)putchar('\n'); |
980f4f50 | 281 | (void)fclose(fp); |
6b8910b8 KB |
282 | return(1); |
283 | } | |
d65ceee1 | 284 | |
516a0fd6 | 285 | static void |
d65ceee1 KB |
286 | vputc(ch) |
287 | register int ch; | |
288 | { | |
289 | int meta; | |
290 | ||
291 | if (!isascii(ch)) { | |
292 | (void)putchar('M'); | |
293 | (void)putchar('-'); | |
294 | ch = toascii(ch); | |
295 | meta = 1; | |
296 | } else | |
297 | meta = 0; | |
d5df533e | 298 | if (isprint(ch) || !meta && (ch == ' ' || ch == '\t' || ch == '\n')) |
d65ceee1 KB |
299 | (void)putchar(ch); |
300 | else { | |
301 | (void)putchar('^'); | |
302 | (void)putchar(ch == '\177' ? '?' : ch | 0100); | |
303 | } | |
304 | } |