]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.bin/finger/lprint.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.bin / finger / lprint.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #if 0
38 #ifndef lint
39 static char sccsid[] = "@(#)lprint.c    8.3 (Berkeley) 4/28/95";
40 #endif
41 #endif
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 #include <ctype.h>
51 #include <db.h>
52 #include <err.h>
53 #include <fcntl.h>
54 #include <langinfo.h>
55 #include <paths.h>
56 #include <pwd.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <utmp.h>
61 #include "finger.h"
62 #include "pathnames.h"
63
64 #define LINE_LEN        80
65 #define TAB_LEN         8               /* 8 spaces between tabs */
66
67 static int      demi_print(char *, int);
68 static void     lprint(PERSON *);
69 static void     vputc(unsigned char);
70
71 void
72 lflag_print(void)
73 {
74         PERSON *pn;
75         int sflag, r;
76         PERSON *tmp;
77         DBT data, key;
78
79         for (sflag = R_FIRST;; sflag = R_NEXT) {
80                 r = (*db->seq)(db, &key, &data, sflag);
81                 if (r == -1)
82                         err(1, "db seq");
83                 if (r == 1)
84                         break;
85                 memmove(&tmp, data.data, sizeof tmp);
86                 pn = tmp;
87                 if (sflag != R_FIRST)
88                         putchar('\n');
89                 lprint(pn);
90                 if (!pplan) {
91                         (void)show_text(pn->dir,
92                             _PATH_FORWARD, "Mail forwarded to");
93                         (void)show_text(pn->dir, _PATH_PROJECT, "Project");
94                         if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
95                                 (void)printf("No Plan.\n");
96                         (void)show_text(pn->dir,
97                             _PATH_PUBKEY, "Public key");
98                 }
99         }
100 }
101
102 static void
103 lprint(PERSON *pn)
104 {
105         struct tm *delta;
106         WHERE *w;
107         int cpr, len, maxlen;
108         struct tm *tp;
109         int oddfield;
110         char t[80];
111
112         if (d_first < 0)
113                 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
114         /*
115          * long format --
116          *      login name
117          *      real name
118          *      home directory
119          *      shell
120          *      office, office phone, home phone if available
121          *      mail status
122          */
123         (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
124             pn->name, pn->realname, pn->dir);
125         (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
126
127         if (gflag)
128                 goto no_gecos;
129         /*
130          * try and print office, office phone, and home phone on one line;
131          * if that fails, do line filling so it looks nice.
132          */
133 #define OFFICE_TAG              "Office"
134 #define OFFICE_PHONE_TAG        "Office Phone"
135         oddfield = 0;
136         if (pn->office && pn->officephone &&
137             strlen(pn->office) + strlen(pn->officephone) +
138             sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
139                 (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s",
140                     OFFICE_TAG, pn->office, prphone(pn->officephone));
141                 oddfield = demi_print(tbuf, oddfield);
142         } else {
143                 if (pn->office) {
144                         (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
145                             OFFICE_TAG, pn->office);
146                         oddfield = demi_print(tbuf, oddfield);
147                 }
148                 if (pn->officephone) {
149                         (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
150                             OFFICE_PHONE_TAG, prphone(pn->officephone));
151                         oddfield = demi_print(tbuf, oddfield);
152                 }
153         }
154         if (pn->homephone) {
155                 (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone",
156                     prphone(pn->homephone));
157                 oddfield = demi_print(tbuf, oddfield);
158         }
159         if (oddfield)
160                 putchar('\n');
161
162 no_gecos:
163         /*
164          * long format con't:
165          * if logged in
166          *      terminal
167          *      idle time
168          *      if messages allowed
169          *      where logged in from
170          * if not logged in
171          *      when last logged in
172          */
173         /* find out longest device name for this user for formatting */
174         for (w = pn->whead, maxlen = -1; w != NULL; w = w->next)
175                 if ((len = strlen(w->tty)) > maxlen)
176                         maxlen = len;
177         /* find rest of entries for user */
178         for (w = pn->whead; w != NULL; w = w->next) {
179                 if (w->info == LOGGEDIN) {
180                         tp = localtime(&w->loginat);
181                         strftime(t, sizeof(t),
182                             d_first ? "%a %e %b %R (%Z)" : "%a %b %e %R (%Z)",
183                             tp);
184                         cpr = printf("On since %s on %s", t, w->tty);
185                         /*
186                          * idle time is tough; if have one, print a comma,
187                          * then spaces to pad out the device name, then the
188                          * idle time.  Follow with a comma if a remote login.
189                          */
190                         delta = gmtime(&w->idletime);
191                         if (w->idletime != -1 && (delta->tm_yday ||
192                             delta->tm_hour || delta->tm_min)) {
193                                 cpr += printf("%-*s idle ",
194                                     maxlen - (int)strlen(w->tty) + 1, ",");
195                                 if (delta->tm_yday > 0) {
196                                         cpr += printf("%d day%s ",
197                                            delta->tm_yday,
198                                            delta->tm_yday == 1 ? "" : "s");
199                                 }
200                                 cpr += printf("%d:%02d",
201                                     delta->tm_hour, delta->tm_min);
202                                 if (*w->host) {
203                                         putchar(',');
204                                         ++cpr;
205                                 }
206                         }
207                         if (!w->writable)
208                                 cpr += printf(" (messages off)");
209                 } else if (w->loginat == 0) {
210                         cpr = printf("Never logged in.");
211                 } else {
212                         tp = localtime(&w->loginat);
213                         if (now - w->loginat > 86400 * 365 / 2) {
214                                 strftime(t, sizeof(t),
215                                          d_first ? "%a %e %b %R %Y (%Z)" :
216                                                    "%a %b %e %R %Y (%Z)",
217                                          tp);
218                         } else {
219                                 strftime(t, sizeof(t),
220                                          d_first ? "%a %e %b %R (%Z)" :
221                                                    "%a %b %e %R (%Z)",
222                                          tp);
223                         }
224                         cpr = printf("Last login %s on %s", t, w->tty);
225                 }
226                 if (*w->host) {
227                         if (LINE_LEN < (cpr + 6 + strlen(w->host)))
228                                 (void)printf("\n   ");
229                         (void)printf(" from %s", w->host);
230                 }
231                 putchar('\n');
232         }
233         if (pn->mailrecv == -1)
234                 printf("No Mail.\n");
235         else if (pn->mailrecv > pn->mailread) {
236                 tp = localtime(&pn->mailrecv);
237                 strftime(t, sizeof(t),
238                          d_first ? "%a %e %b %R %Y (%Z)" :
239                                    "%a %b %e %R %Y (%Z)",
240                          tp);
241                 printf("New mail received %s\n", t);
242                 tp = localtime(&pn->mailread);
243                 strftime(t, sizeof(t),
244                          d_first ? "%a %e %b %R %Y (%Z)" :
245                                    "%a %b %e %R %Y (%Z)",
246                          tp);
247                 printf("     Unread since %s\n", t);
248         } else {
249                 tp = localtime(&pn->mailread);
250                 strftime(t, sizeof(t),
251                          d_first ? "%a %e %b %R %Y (%Z)" :
252                                    "%a %b %e %R %Y (%Z)",
253                          tp);
254                 printf("Mail last read %s\n", t);
255         }
256 }
257
258 static int
259 demi_print(char *str, int oddfield)
260 {
261         static int lenlast;
262         int lenthis, maxlen;
263
264         lenthis = strlen(str);
265         if (oddfield) {
266                 /*
267                  * We left off on an odd number of fields.  If we haven't
268                  * crossed the midpoint of the screen, and we have room for
269                  * the next field, print it on the same line; otherwise,
270                  * print it on a new line.
271                  *
272                  * Note: we insist on having the right hand fields start
273                  * no less than 5 tabs out.
274                  */
275                 maxlen = 5 * TAB_LEN;
276                 if (maxlen < lenlast)
277                         maxlen = lenlast;
278                 if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
279                     lenthis) <= LINE_LEN) {
280                         while(lenlast < (4 * TAB_LEN)) {
281                                 putchar('\t');
282                                 lenlast += TAB_LEN;
283                         }
284                         (void)printf("\t%s\n", str);    /* force one tab */
285                 } else {
286                         (void)printf("\n%s", str);      /* go to next line */
287                         oddfield = !oddfield;   /* this'll be undone below */
288                 }
289         } else
290                 (void)printf("%s", str);
291         oddfield = !oddfield;                   /* toggle odd/even marker */
292         lenlast = lenthis;
293         return(oddfield);
294 }
295
296 int
297 show_text(const char *directory, const char *file_name, const char *header)
298 {
299         struct stat sb;
300         FILE *fp;
301         int ch, cnt;
302         char *p, lastc;
303         int fd, nr;
304
305         lastc = '\0';
306
307         (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
308         if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
309             sb.st_size == 0)
310                 return(0);
311
312         /* If short enough, and no newlines, show it on a single line.*/
313         if (sb.st_size <= LINE_LEN - strlen(header) - 5) {
314                 nr = read(fd, tbuf, sizeof(tbuf));
315                 if (nr <= 0) {
316                         (void)close(fd);
317                         return(0);
318                 }
319                 for (p = tbuf, cnt = nr; cnt--; ++p)
320                         if (*p == '\n')
321                                 break;
322                 if (cnt <= 1) {
323                         if (*header != '\0')
324                                 (void)printf("%s: ", header);
325                         for (p = tbuf, cnt = nr; cnt--; ++p)
326                                 if (*p != '\r')
327                                         vputc(lastc = *p);
328                         if (lastc != '\n')
329                                 (void)putchar('\n');
330                         (void)close(fd);
331                         return(1);
332                 }
333                 else
334                         (void)lseek(fd, 0L, SEEK_SET);
335         }
336         if ((fp = fdopen(fd, "r")) == NULL)
337                 return(0);
338         if (*header != '\0')
339                 (void)printf("%s:\n", header);
340         while ((ch = getc(fp)) != EOF)
341                 if (ch != '\r')
342                         vputc(lastc = ch);
343         if (lastc != '\n')
344                 (void)putchar('\n');
345         (void)fclose(fp);
346         return(1);
347 }
348
349 static void
350 vputc(unsigned char ch)
351 {
352         int meta;
353
354         if (!isprint(ch) && !isascii(ch)) {
355                 (void)putchar('M');
356                 (void)putchar('-');
357                 ch = toascii(ch);
358                 meta = 1;
359         } else
360                 meta = 0;
361         if (isprint(ch) || (!meta && (ch == ' ' || ch == '\t' || ch == '\n')))
362                 (void)putchar(ch);
363         else {
364                 (void)putchar('^');
365                 (void)putchar(ch == '\177' ? '?' : ch | 0100);
366         }
367 }