11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 3387628Sdwmalone#if 0 3487628Sdwmalone#ifndef lint 3587628Sdwmalonestatic char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95"; 3687628Sdwmalone#endif 3787628Sdwmalone#endif 3887628Sdwmalone 3987229Smarkm#include <sys/cdefs.h> 4087229Smarkm__FBSDID("$FreeBSD: releng/10.3/usr.bin/finger/lprint.c 226358 2011-10-14 07:24:23Z ed $"); 4187229Smarkm 4291226Sbde#include <sys/types.h> 43102944Sdwmalone#include <sys/socket.h> 441590Srgrimes#include <sys/stat.h> 4591226Sbde#include <sys/time.h> 4672109Scharnier#include <ctype.h> 471590Srgrimes#include <db.h> 4823693Speter#include <err.h> 4972109Scharnier#include <fcntl.h> 5074586Sache#include <langinfo.h> 5172109Scharnier#include <paths.h> 521590Srgrimes#include <pwd.h> 531590Srgrimes#include <stdio.h> 541590Srgrimes#include <string.h> 5572109Scharnier#include <unistd.h> 56202191Sed#include <utmpx.h> 571590Srgrimes#include "finger.h" 5865064Sbrian#include "pathnames.h" 591590Srgrimes 601590Srgrimes#define LINE_LEN 80 611590Srgrimes#define TAB_LEN 8 /* 8 spaces between tabs */ 621590Srgrimes 6392920Simpstatic int demi_print(char *, int); 6492920Simpstatic void lprint(PERSON *); 6592920Simpstatic void vputc(unsigned char); 661590Srgrimes 671590Srgrimesvoid 68102944Sdwmalonelflag_print(void) 691590Srgrimes{ 7087229Smarkm PERSON *pn; 7187229Smarkm int sflag, r; 7223693Speter PERSON *tmp; 731590Srgrimes DBT data, key; 741590Srgrimes 751590Srgrimes for (sflag = R_FIRST;; sflag = R_NEXT) { 761590Srgrimes r = (*db->seq)(db, &key, &data, sflag); 771590Srgrimes if (r == -1) 7823693Speter err(1, "db seq"); 791590Srgrimes if (r == 1) 801590Srgrimes break; 8123693Speter memmove(&tmp, data.data, sizeof tmp); 8223693Speter pn = tmp; 831590Srgrimes if (sflag != R_FIRST) 841590Srgrimes putchar('\n'); 851590Srgrimes lprint(pn); 861590Srgrimes if (!pplan) { 871590Srgrimes (void)show_text(pn->dir, 881590Srgrimes _PATH_FORWARD, "Mail forwarded to"); 891590Srgrimes (void)show_text(pn->dir, _PATH_PROJECT, "Project"); 901590Srgrimes if (!show_text(pn->dir, _PATH_PLAN, "Plan")) 911590Srgrimes (void)printf("No Plan.\n"); 9270474Sdes (void)show_text(pn->dir, 9370655Sdes _PATH_PUBKEY, "Public key"); 941590Srgrimes } 951590Srgrimes } 961590Srgrimes} 971590Srgrimes 981590Srgrimesstatic void 99102944Sdwmalonelprint(PERSON *pn) 1001590Srgrimes{ 10187229Smarkm struct tm *delta; 10287229Smarkm WHERE *w; 10387229Smarkm int cpr, len, maxlen; 1041590Srgrimes struct tm *tp; 1051590Srgrimes int oddfield; 1069993Sache char t[80]; 1071590Srgrimes 10874586Sache if (d_first < 0) 10974586Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 1101590Srgrimes /* 1111590Srgrimes * long format -- 1121590Srgrimes * login name 1131590Srgrimes * real name 1141590Srgrimes * home directory 1151590Srgrimes * shell 1161590Srgrimes * office, office phone, home phone if available 1172537Spst * mail status 1181590Srgrimes */ 1191590Srgrimes (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", 1201590Srgrimes pn->name, pn->realname, pn->dir); 1211590Srgrimes (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); 1221590Srgrimes 12399249Smini if (gflag) 12499249Smini goto no_gecos; 1251590Srgrimes /* 1261590Srgrimes * try and print office, office phone, and home phone on one line; 1271590Srgrimes * if that fails, do line filling so it looks nice. 1281590Srgrimes */ 1291590Srgrimes#define OFFICE_TAG "Office" 1301590Srgrimes#define OFFICE_PHONE_TAG "Office Phone" 1311590Srgrimes oddfield = 0; 1321590Srgrimes if (pn->office && pn->officephone && 1331590Srgrimes strlen(pn->office) + strlen(pn->officephone) + 1341590Srgrimes sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { 1351590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s", 1361590Srgrimes OFFICE_TAG, pn->office, prphone(pn->officephone)); 1371590Srgrimes oddfield = demi_print(tbuf, oddfield); 1381590Srgrimes } else { 1391590Srgrimes if (pn->office) { 1401590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", 1411590Srgrimes OFFICE_TAG, pn->office); 1421590Srgrimes oddfield = demi_print(tbuf, oddfield); 1431590Srgrimes } 1441590Srgrimes if (pn->officephone) { 1451590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", 1461590Srgrimes OFFICE_PHONE_TAG, prphone(pn->officephone)); 1471590Srgrimes oddfield = demi_print(tbuf, oddfield); 1481590Srgrimes } 1491590Srgrimes } 1501590Srgrimes if (pn->homephone) { 1511590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone", 1521590Srgrimes prphone(pn->homephone)); 1531590Srgrimes oddfield = demi_print(tbuf, oddfield); 1541590Srgrimes } 1551590Srgrimes if (oddfield) 1561590Srgrimes putchar('\n'); 1571590Srgrimes 15899249Sminino_gecos: 1591590Srgrimes /* 1602537Spst * long format con't: 1612537Spst * if logged in 1621590Srgrimes * terminal 1631590Srgrimes * idle time 1641590Srgrimes * if messages allowed 1651590Srgrimes * where logged in from 1661590Srgrimes * if not logged in 1671590Srgrimes * when last logged in 1681590Srgrimes */ 1691590Srgrimes /* find out longest device name for this user for formatting */ 1701590Srgrimes for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) 1711590Srgrimes if ((len = strlen(w->tty)) > maxlen) 1721590Srgrimes maxlen = len; 1731590Srgrimes /* find rest of entries for user */ 1741590Srgrimes for (w = pn->whead; w != NULL; w = w->next) { 17567467Sru if (w->info == LOGGEDIN) { 1761590Srgrimes tp = localtime(&w->loginat); 17774586Sache strftime(t, sizeof(t), 17874586Sache d_first ? "%a %e %b %R (%Z)" : "%a %b %e %R (%Z)", 17974586Sache tp); 18074586Sache cpr = printf("On since %s on %s", t, w->tty); 1811590Srgrimes /* 1821590Srgrimes * idle time is tough; if have one, print a comma, 1831590Srgrimes * then spaces to pad out the device name, then the 1841590Srgrimes * idle time. Follow with a comma if a remote login. 1851590Srgrimes */ 1861590Srgrimes delta = gmtime(&w->idletime); 187112987Srwatson if (w->idletime != -1 && (delta->tm_yday || 188112987Srwatson delta->tm_hour || delta->tm_min)) { 1891590Srgrimes cpr += printf("%-*s idle ", 19090390Speter maxlen - (int)strlen(w->tty) + 1, ","); 1911590Srgrimes if (delta->tm_yday > 0) { 1921590Srgrimes cpr += printf("%d day%s ", 1931590Srgrimes delta->tm_yday, 1941590Srgrimes delta->tm_yday == 1 ? "" : "s"); 1951590Srgrimes } 1961590Srgrimes cpr += printf("%d:%02d", 1971590Srgrimes delta->tm_hour, delta->tm_min); 1981590Srgrimes if (*w->host) { 1991590Srgrimes putchar(','); 2001590Srgrimes ++cpr; 2011590Srgrimes } 2021590Srgrimes } 2031590Srgrimes if (!w->writable) 2041590Srgrimes cpr += printf(" (messages off)"); 20567467Sru } else if (w->loginat == 0) { 20667467Sru cpr = printf("Never logged in."); 20767467Sru } else { 2081590Srgrimes tp = localtime(&w->loginat); 20974586Sache if (now - w->loginat > 86400 * 365 / 2) { 21074586Sache strftime(t, sizeof(t), 21174586Sache d_first ? "%a %e %b %R %Y (%Z)" : 21274586Sache "%a %b %e %R %Y (%Z)", 21374586Sache tp); 21474586Sache } else { 21574586Sache strftime(t, sizeof(t), 21674586Sache d_first ? "%a %e %b %R (%Z)" : 21774586Sache "%a %b %e %R (%Z)", 21874586Sache tp); 21974586Sache } 22074586Sache cpr = printf("Last login %s on %s", t, w->tty); 2211590Srgrimes } 2221590Srgrimes if (*w->host) { 2231590Srgrimes if (LINE_LEN < (cpr + 6 + strlen(w->host))) 2241590Srgrimes (void)printf("\n "); 2251590Srgrimes (void)printf(" from %s", w->host); 2261590Srgrimes } 2271590Srgrimes putchar('\n'); 2281590Srgrimes } 2292537Spst if (pn->mailrecv == -1) 2302537Spst printf("No Mail.\n"); 2312537Spst else if (pn->mailrecv > pn->mailread) { 2322537Spst tp = localtime(&pn->mailrecv); 23374586Sache strftime(t, sizeof(t), 23474586Sache d_first ? "%a %e %b %R %Y (%Z)" : 23574586Sache "%a %b %e %R %Y (%Z)", 23674586Sache tp); 23774586Sache printf("New mail received %s\n", t); 2382537Spst tp = localtime(&pn->mailread); 23974586Sache strftime(t, sizeof(t), 24074586Sache d_first ? "%a %e %b %R %Y (%Z)" : 24174586Sache "%a %b %e %R %Y (%Z)", 24274586Sache tp); 24374586Sache printf(" Unread since %s\n", t); 2442537Spst } else { 2452537Spst tp = localtime(&pn->mailread); 24674586Sache strftime(t, sizeof(t), 24774586Sache d_first ? "%a %e %b %R %Y (%Z)" : 24874586Sache "%a %b %e %R %Y (%Z)", 24974586Sache tp); 25074586Sache printf("Mail last read %s\n", t); 2512537Spst } 2521590Srgrimes} 2531590Srgrimes 2541590Srgrimesstatic int 255102944Sdwmalonedemi_print(char *str, int oddfield) 2561590Srgrimes{ 2571590Srgrimes static int lenlast; 2581590Srgrimes int lenthis, maxlen; 2591590Srgrimes 2601590Srgrimes lenthis = strlen(str); 2611590Srgrimes if (oddfield) { 2621590Srgrimes /* 2631590Srgrimes * We left off on an odd number of fields. If we haven't 2641590Srgrimes * crossed the midpoint of the screen, and we have room for 2651590Srgrimes * the next field, print it on the same line; otherwise, 2661590Srgrimes * print it on a new line. 2671590Srgrimes * 2681590Srgrimes * Note: we insist on having the right hand fields start 2691590Srgrimes * no less than 5 tabs out. 2701590Srgrimes */ 2711590Srgrimes maxlen = 5 * TAB_LEN; 2721590Srgrimes if (maxlen < lenlast) 2731590Srgrimes maxlen = lenlast; 2741590Srgrimes if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + 2751590Srgrimes lenthis) <= LINE_LEN) { 2761590Srgrimes while(lenlast < (4 * TAB_LEN)) { 2771590Srgrimes putchar('\t'); 2781590Srgrimes lenlast += TAB_LEN; 2791590Srgrimes } 2801590Srgrimes (void)printf("\t%s\n", str); /* force one tab */ 2811590Srgrimes } else { 2821590Srgrimes (void)printf("\n%s", str); /* go to next line */ 2831590Srgrimes oddfield = !oddfield; /* this'll be undone below */ 2841590Srgrimes } 2851590Srgrimes } else 2861590Srgrimes (void)printf("%s", str); 2871590Srgrimes oddfield = !oddfield; /* toggle odd/even marker */ 2881590Srgrimes lenlast = lenthis; 2891590Srgrimes return(oddfield); 2901590Srgrimes} 2911590Srgrimes 29265064Sbrianint 293102944Sdwmaloneshow_text(const char *directory, const char *file_name, const char *header) 2941590Srgrimes{ 2951590Srgrimes struct stat sb; 29687229Smarkm FILE *fp; 29787229Smarkm int ch, cnt; 29887229Smarkm char *p, lastc; 2991590Srgrimes int fd, nr; 3001590Srgrimes 30167467Sru lastc = '\0'; 30267467Sru 3031590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); 3041590Srgrimes if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || 3051590Srgrimes sb.st_size == 0) 3061590Srgrimes return(0); 3071590Srgrimes 3081590Srgrimes /* If short enough, and no newlines, show it on a single line.*/ 309226358Sed if (sb.st_size <= (off_t)(LINE_LEN - strlen(header) - 5)) { 3101590Srgrimes nr = read(fd, tbuf, sizeof(tbuf)); 3111590Srgrimes if (nr <= 0) { 3121590Srgrimes (void)close(fd); 3131590Srgrimes return(0); 3141590Srgrimes } 3151590Srgrimes for (p = tbuf, cnt = nr; cnt--; ++p) 3161590Srgrimes if (*p == '\n') 3171590Srgrimes break; 3181590Srgrimes if (cnt <= 1) { 31965064Sbrian if (*header != '\0') 32065064Sbrian (void)printf("%s: ", header); 3211590Srgrimes for (p = tbuf, cnt = nr; cnt--; ++p) 32223971Sache if (*p != '\r') 32323971Sache vputc(lastc = *p); 3241590Srgrimes if (lastc != '\n') 3251590Srgrimes (void)putchar('\n'); 3261590Srgrimes (void)close(fd); 3271590Srgrimes return(1); 3281590Srgrimes } 3291590Srgrimes else 3301590Srgrimes (void)lseek(fd, 0L, SEEK_SET); 3311590Srgrimes } 3321590Srgrimes if ((fp = fdopen(fd, "r")) == NULL) 3331590Srgrimes return(0); 33465064Sbrian if (*header != '\0') 33565064Sbrian (void)printf("%s:\n", header); 3361590Srgrimes while ((ch = getc(fp)) != EOF) 33723971Sache if (ch != '\r') 33823971Sache vputc(lastc = ch); 3391590Srgrimes if (lastc != '\n') 3401590Srgrimes (void)putchar('\n'); 3411590Srgrimes (void)fclose(fp); 3421590Srgrimes return(1); 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimesstatic void 346102944Sdwmalonevputc(unsigned char ch) 3471590Srgrimes{ 3481590Srgrimes int meta; 3491590Srgrimes 3509994Sache if (!isprint(ch) && !isascii(ch)) { 3511590Srgrimes (void)putchar('M'); 3521590Srgrimes (void)putchar('-'); 3531590Srgrimes ch = toascii(ch); 3541590Srgrimes meta = 1; 3551590Srgrimes } else 3561590Srgrimes meta = 0; 35767467Sru if (isprint(ch) || (!meta && (ch == ' ' || ch == '\t' || ch == '\n'))) 3581590Srgrimes (void)putchar(ch); 3591590Srgrimes else { 3601590Srgrimes (void)putchar('^'); 3611590Srgrimes (void)putchar(ch == '\177' ? '?' : ch | 0100); 3621590Srgrimes } 3631590Srgrimes} 364