lprint.c revision 23971
133965Sjdp/* 2218822Sdim * Copyright (c) 1989, 1993 3218822Sdim * The Regents of the University of California. All rights reserved. 477298Sobrien * 533965Sjdp * This code is derived from software contributed to Berkeley by 633965Sjdp * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1433965Sjdp * notice, this list of conditions and the following disclaimer in the 1533965Sjdp * documentation and/or other materials provided with the distribution. 1633965Sjdp * 3. All advertising materials mentioning features or use of this software 1733965Sjdp * must display the following acknowledgement: 1833965Sjdp * This product includes software developed by the University of 1933965Sjdp * California, Berkeley and its contributors. 20218822Sdim * 4. Neither the name of the University nor the names of its contributors 21218822Sdim * may be used to endorse or promote products derived from this software 2233965Sjdp * without specific prior written permission. 2360484Sobrien * 2460484Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2560484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2733965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28130561Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30130561Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3433965Sjdp * SUCH DAMAGE. 3533965Sjdp */ 3633965Sjdp 3733965Sjdp#ifndef lint 3833965Sjdpstatic char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95"; 3933965Sjdp#endif /* not lint */ 4033965Sjdp 4133965Sjdp#include <sys/types.h> 4233965Sjdp#include <sys/stat.h> 4333965Sjdp#include <sys/time.h> 4433965Sjdp#include <fcntl.h> 4533965Sjdp#include <time.h> 4633965Sjdp#include <db.h> 47218822Sdim#include <err.h> 4833965Sjdp#include <pwd.h> 4933965Sjdp#include <utmp.h> 50218822Sdim#include <errno.h> 5133965Sjdp#include <unistd.h> 52218822Sdim#include <stdio.h> 5333965Sjdp#include <ctype.h> 5433965Sjdp#include <string.h> 5533965Sjdp#include <paths.h> 5633965Sjdp#include "finger.h" 5733965Sjdp 5833965Sjdp#define LINE_LEN 80 5933965Sjdp#define TAB_LEN 8 /* 8 spaces between tabs */ 6033965Sjdp#define _PATH_FORWARD ".forward" 6133965Sjdp#define _PATH_PLAN ".plan" 6233965Sjdp#define _PATH_PROJECT ".project" 6333965Sjdp 6433965Sjdpstatic int demi_print __P((char *, int)); 6533965Sjdpstatic void lprint __P((PERSON *)); 6633965Sjdpstatic int show_text __P((char *, char *, char *)); 67218822Sdimstatic void vputc __P((int)); 68218822Sdim 69218822Sdimvoid 70218822Sdimlflag_print() 71218822Sdim{ 72218822Sdim extern int pplan; 7333965Sjdp register PERSON *pn; 7433965Sjdp register int sflag, r; 7533965Sjdp PERSON *tmp; 7633965Sjdp DBT data, key; 7733965Sjdp 7833965Sjdp for (sflag = R_FIRST;; sflag = R_NEXT) { 7977298Sobrien r = (*db->seq)(db, &key, &data, sflag); 8033965Sjdp if (r == -1) 8133965Sjdp err(1, "db seq"); 8277298Sobrien if (r == 1) 8333965Sjdp break; 8433965Sjdp memmove(&tmp, data.data, sizeof tmp); 8577298Sobrien pn = tmp; 8633965Sjdp if (sflag != R_FIRST) 8733965Sjdp putchar('\n'); 88130561Sobrien lprint(pn); 89130561Sobrien if (!pplan) { 90130561Sobrien (void)show_text(pn->dir, 9133965Sjdp _PATH_FORWARD, "Mail forwarded to"); 9233965Sjdp (void)show_text(pn->dir, _PATH_PROJECT, "Project"); 9333965Sjdp if (!show_text(pn->dir, _PATH_PLAN, "Plan")) 9433965Sjdp (void)printf("No Plan.\n"); 9533965Sjdp } 9633965Sjdp } 9733965Sjdp} 9833965Sjdp 9933965Sjdpstatic void 10033965Sjdplprint(pn) 10133965Sjdp register PERSON *pn; 10233965Sjdp{ 10333965Sjdp extern time_t now; 10433965Sjdp register struct tm *delta; 10533965Sjdp register WHERE *w; 10633965Sjdp register int cpr, len, maxlen; 10733965Sjdp struct tm *tp; 10833965Sjdp int oddfield; 10933965Sjdp char *tzn; 11033965Sjdp char t[80]; 11133965Sjdp 11233965Sjdp /* 11333965Sjdp * long format -- 11433965Sjdp * login name 11533965Sjdp * real name 11633965Sjdp * home directory 11760484Sobrien * shell 11860484Sobrien * office, office phone, home phone if available 11960484Sobrien * mail status 12060484Sobrien */ 12160484Sobrien (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", 12260484Sobrien pn->name, pn->realname, pn->dir); 123218822Sdim (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); 124218822Sdim 125218822Sdim /* 126218822Sdim * try and print office, office phone, and home phone on one line; 12760484Sobrien * if that fails, do line filling so it looks nice. 12860484Sobrien */ 12960484Sobrien#define OFFICE_TAG "Office" 13033965Sjdp#define OFFICE_PHONE_TAG "Office Phone" 13133965Sjdp oddfield = 0; 13233965Sjdp if (pn->office && pn->officephone && 13333965Sjdp strlen(pn->office) + strlen(pn->officephone) + 13433965Sjdp sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { 13533965Sjdp (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s", 13633965Sjdp OFFICE_TAG, pn->office, prphone(pn->officephone)); 13733965Sjdp oddfield = demi_print(tbuf, oddfield); 13833965Sjdp } else { 139218822Sdim if (pn->office) { 140218822Sdim (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", 141218822Sdim OFFICE_TAG, pn->office); 142218822Sdim oddfield = demi_print(tbuf, oddfield); 143218822Sdim } 144218822Sdim if (pn->officephone) { 145218822Sdim (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", 146218822Sdim OFFICE_PHONE_TAG, prphone(pn->officephone)); 147218822Sdim oddfield = demi_print(tbuf, oddfield); 148218822Sdim } 149218822Sdim } 150218822Sdim if (pn->homephone) { 151218822Sdim (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone", 152218822Sdim prphone(pn->homephone)); 153218822Sdim oddfield = demi_print(tbuf, oddfield); 154218822Sdim } 155218822Sdim if (oddfield) 156218822Sdim putchar('\n'); 157218822Sdim 158218822Sdim /* 159218822Sdim * long format con't: 160218822Sdim * if logged in 161218822Sdim * terminal 16289857Sobrien * idle time 163130561Sobrien * if messages allowed 164130561Sobrien * where logged in from 165218822Sdim * if not logged in 16689857Sobrien * when last logged in 167130561Sobrien */ 168130561Sobrien /* find out longest device name for this user for formatting */ 169130561Sobrien for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) 170130561Sobrien if ((len = strlen(w->tty)) > maxlen) 171130561Sobrien maxlen = len; 172130561Sobrien /* find rest of entries for user */ 173218822Sdim for (w = pn->whead; w != NULL; w = w->next) { 174130561Sobrien switch (w->info) { 175130561Sobrien case LOGGEDIN: 17633965Sjdp tp = localtime(&w->loginat); 177130561Sobrien strftime(t, sizeof(t), "%c", tp); 178130561Sobrien tzn = tp->tm_zone; 17933965Sjdp cpr = printf("On since %.16s (%s) on %s", 180130561Sobrien t, tzn, w->tty); 181130561Sobrien /* 182130561Sobrien * idle time is tough; if have one, print a comma, 18333965Sjdp * then spaces to pad out the device name, then the 18460484Sobrien * idle time. Follow with a comma if a remote login. 185 */ 186 delta = gmtime(&w->idletime); 187 if (delta->tm_yday || delta->tm_hour || delta->tm_min) { 188 cpr += printf("%-*s idle ", 189 maxlen - strlen(w->tty) + 1, ","); 190 if (delta->tm_yday > 0) { 191 cpr += printf("%d day%s ", 192 delta->tm_yday, 193 delta->tm_yday == 1 ? "" : "s"); 194 } 195 cpr += printf("%d:%02d", 196 delta->tm_hour, delta->tm_min); 197 if (*w->host) { 198 putchar(','); 199 ++cpr; 200 } 201 } 202 if (!w->writable) 203 cpr += printf(" (messages off)"); 204 break; 205 case LASTLOG: 206 if (w->loginat == 0) { 207 (void)printf("Never logged in."); 208 break; 209 } 210 tp = localtime(&w->loginat); 211 strftime(t, sizeof(t), "%c", tp); 212 tzn = tp->tm_zone; 213 if (now - w->loginat > 86400 * 365 / 2) 214 cpr = 215 printf("Last login %.16s %.4s (%s) on %s", 216 t, t + 20, tzn, w->tty); 217 else 218 cpr = printf("Last login %.16s (%s) on %s", 219 t, tzn, w->tty); 220 break; 221 } 222 if (*w->host) { 223 if (LINE_LEN < (cpr + 6 + strlen(w->host))) 224 (void)printf("\n "); 225 (void)printf(" from %s", w->host); 226 } 227 putchar('\n'); 228 } 229 if (pn->mailrecv == -1) 230 printf("No Mail.\n"); 231 else if (pn->mailrecv > pn->mailread) { 232 tp = localtime(&pn->mailrecv); 233 strftime(t, sizeof(t), "%c", tp); 234 tzn = tp->tm_zone; 235 printf("New mail received %.16s %.4s (%s)\n", t, t + 20, tzn); 236 tp = localtime(&pn->mailread); 237 strftime(t, sizeof(t), "%c", tp); 238 tzn = tp->tm_zone; 239 printf(" Unread since %.16s %.4s (%s)\n", t, t + 20, tzn); 240 } else { 241 tp = localtime(&pn->mailread); 242 strftime(t, sizeof(t), "%c", tp); 243 tzn = tp->tm_zone; 244 printf("Mail last read %.16s %.4s (%s)\n", t, t + 20, tzn); 245 } 246} 247 248static int 249demi_print(str, oddfield) 250 char *str; 251 int oddfield; 252{ 253 static int lenlast; 254 int lenthis, maxlen; 255 256 lenthis = strlen(str); 257 if (oddfield) { 258 /* 259 * We left off on an odd number of fields. If we haven't 260 * crossed the midpoint of the screen, and we have room for 261 * the next field, print it on the same line; otherwise, 262 * print it on a new line. 263 * 264 * Note: we insist on having the right hand fields start 265 * no less than 5 tabs out. 266 */ 267 maxlen = 5 * TAB_LEN; 268 if (maxlen < lenlast) 269 maxlen = lenlast; 270 if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + 271 lenthis) <= LINE_LEN) { 272 while(lenlast < (4 * TAB_LEN)) { 273 putchar('\t'); 274 lenlast += TAB_LEN; 275 } 276 (void)printf("\t%s\n", str); /* force one tab */ 277 } else { 278 (void)printf("\n%s", str); /* go to next line */ 279 oddfield = !oddfield; /* this'll be undone below */ 280 } 281 } else 282 (void)printf("%s", str); 283 oddfield = !oddfield; /* toggle odd/even marker */ 284 lenlast = lenthis; 285 return(oddfield); 286} 287 288static int 289show_text(directory, file_name, header) 290 char *directory, *file_name, *header; 291{ 292 struct stat sb; 293 register FILE *fp; 294 register int ch, cnt, lastc; 295 register char *p; 296 int fd, nr; 297 298 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); 299 if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || 300 sb.st_size == 0) 301 return(0); 302 303 /* If short enough, and no newlines, show it on a single line.*/ 304 if (sb.st_size <= LINE_LEN - strlen(header) - 5) { 305 nr = read(fd, tbuf, sizeof(tbuf)); 306 if (nr <= 0) { 307 (void)close(fd); 308 return(0); 309 } 310 for (p = tbuf, cnt = nr; cnt--; ++p) 311 if (*p == '\n') 312 break; 313 if (cnt <= 1) { 314 (void)printf("%s: ", header); 315 for (p = tbuf, cnt = nr; cnt--; ++p) 316 if (*p != '\r') 317 vputc(lastc = *p); 318 if (lastc != '\n') 319 (void)putchar('\n'); 320 (void)close(fd); 321 return(1); 322 } 323 else 324 (void)lseek(fd, 0L, SEEK_SET); 325 } 326 if ((fp = fdopen(fd, "r")) == NULL) 327 return(0); 328 (void)printf("%s:\n", header); 329 while ((ch = getc(fp)) != EOF) 330 if (ch != '\r') 331 vputc(lastc = ch); 332 if (lastc != '\n') 333 (void)putchar('\n'); 334 (void)fclose(fp); 335 return(1); 336} 337 338static void 339vputc(ch) 340 register int ch; 341{ 342 int meta; 343 344 if (!isprint(ch) && !isascii(ch)) { 345 (void)putchar('M'); 346 (void)putchar('-'); 347 ch = toascii(ch); 348 meta = 1; 349 } else 350 meta = 0; 351 if (isprint(ch) || !meta && (ch == ' ' || ch == '\t' || ch == '\n')) 352 (void)putchar(ch); 353 else { 354 (void)putchar('^'); 355 (void)putchar(ch == '\177' ? '?' : ch | 0100); 356 } 357} 358