msgs.c revision 49061
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3527751Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 4127751Scharnier#if 0 4227751Scharnierstatic char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95"; 4327751Scharnier#endif 4427751Scharnierstatic const char rcsid[] = 4549061Smjacob "$Id: msgs.c,v 1.13 1998/07/14 19:07:30 ghelmer Exp $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * msgs - a user bulletin board program 501590Srgrimes * 511590Srgrimes * usage: 521590Srgrimes * msgs [fhlopq] [[-]number] to read messages 531590Srgrimes * msgs -s to place messages 541590Srgrimes * msgs -c [-days] to clean up the bulletin board 551590Srgrimes * 561590Srgrimes * prompt commands are: 571590Srgrimes * y print message 581590Srgrimes * n flush message, go to next message 591590Srgrimes * q flush message, quit 601590Srgrimes * p print message, turn on 'pipe thru more' mode 611590Srgrimes * P print message, turn off 'pipe thru more' mode 621590Srgrimes * - reprint last message 631590Srgrimes * s[-][<num>] [<filename>] save message 641590Srgrimes * m[-][<num>] mail with message in temp mbox 651590Srgrimes * x exit without flushing this message 661590Srgrimes * <num> print message number <num> 671590Srgrimes */ 681590Srgrimes 691590Srgrimes#define V7 /* will look for TERM in the environment */ 701590Srgrimes#define OBJECT /* will object to messages without Subjects */ 718382Srgrimes/* #define REJECT */ /* will reject messages without Subjects 721590Srgrimes (OBJECT must be defined also) */ 738382Srgrimes/* #define UNBUFFERED *//* use unbuffered output */ 741590Srgrimes 751590Srgrimes#include <sys/param.h> 761590Srgrimes#include <sys/stat.h> 771590Srgrimes#include <ctype.h> 7818485Sbde#include <dirent.h> 7927751Scharnier#include <err.h> 801590Srgrimes#include <errno.h> 8137534Sghelmer#include <fcntl.h> 8212809Sache#include <locale.h> 831590Srgrimes#include <pwd.h> 841590Srgrimes#include <setjmp.h> 8527751Scharnier#include <termcap.h> 866591Swollman#include <termios.h> 871590Srgrimes#include <signal.h> 881590Srgrimes#include <stdio.h> 891590Srgrimes#include <stdlib.h> 901590Srgrimes#include <string.h> 911590Srgrimes#include <time.h> 921590Srgrimes#include <unistd.h> 931590Srgrimes#include "pathnames.h" 941590Srgrimes 9512390Sache#define CMODE 0644 /* bounds file creation mode */ 961590Srgrimes#define NO 0 971590Srgrimes#define YES 1 981590Srgrimes#define SUPERUSER 0 /* superuser uid */ 991590Srgrimes#define DAEMON 1 /* daemon uid */ 1001590Srgrimes#define NLINES 24 /* default number of lines/crt screen */ 1011590Srgrimes#define NDAYS 21 /* default keep time for messages */ 1021590Srgrimes#define DAYS *24*60*60 /* seconds/day */ 1031590Srgrimes#define MSGSRC ".msgsrc" /* user's rc file */ 1041590Srgrimes#define BOUNDS "bounds" /* message bounds file */ 1051590Srgrimes#define NEXT "Next message? [yq]" 1061590Srgrimes#define MORE "More? [ynq]" 1071590Srgrimes#define NOMORE "(No more) [q] ?" 1081590Srgrimes 1091590Srgrimestypedef char bool; 1101590Srgrimes 1111590SrgrimesFILE *msgsrc; 1121590SrgrimesFILE *newmsg; 1131590Srgrimeschar *sep = "-"; 1141590Srgrimeschar inbuf[BUFSIZ]; 11527751Scharnierchar fname[MAXPATHLEN]; 11627751Scharnierchar cmdbuf[MAXPATHLEN + MAXPATHLEN]; 1171590Srgrimeschar subj[128]; 1181590Srgrimeschar from[128]; 1191590Srgrimeschar date[128]; 1201590Srgrimeschar *ptr; 1211590Srgrimeschar *in; 1221590Srgrimesbool local; 1231590Srgrimesbool ruptible; 1241590Srgrimesbool totty; 1251590Srgrimesbool seenfrom; 1261590Srgrimesbool seensubj; 1271590Srgrimesbool blankline; 1281590Srgrimesbool printing = NO; 1291590Srgrimesbool mailing = NO; 1301590Srgrimesbool quitit = NO; 1311590Srgrimesbool sending = NO; 1321590Srgrimesbool intrpflg = NO; 1331590Srgrimesint uid; 1341590Srgrimesint msg; 1351590Srgrimesint prevmsg; 1361590Srgrimesint lct; 1371590Srgrimesint nlines; 1381590Srgrimesint Lpp = 0; 1391590Srgrimestime_t t; 1401590Srgrimestime_t keep; 1411590Srgrimes 1421590Srgrimes/* option initialization */ 1431590Srgrimesbool hdrs = NO; 1441590Srgrimesbool qopt = NO; 1451590Srgrimesbool hush = NO; 1461590Srgrimesbool send_msg = NO; 1471590Srgrimesbool locomode = NO; 1481590Srgrimesbool use_pager = NO; 1491590Srgrimesbool clean = NO; 1501590Srgrimesbool lastcmd = NO; 1511590Srgrimesjmp_buf tstpbuf; 1521590Srgrimes 15327751Scharnier 15427751Scharniervoid ask __P((char *)); 15527751Scharniervoid gfrsub __P((FILE *)); 15627751Scharnierint linecnt __P((FILE *)); 15727751Scharnierint next __P((char *)); 15827751Scharnierchar *nxtfld __P((unsigned char *)); 15927751Scharniervoid onsusp __P((int)); 16027751Scharniervoid onintr __P((int)); 16127751Scharniervoid prmesg __P((int)); 16227751Scharnierstatic void usage __P((void)); 16327751Scharnier 16427751Scharnierint 1651590Srgrimesmain(argc, argv) 1661590Srgrimesint argc; char *argv[]; 1671590Srgrimes{ 1681590Srgrimes bool newrc, already; 1691590Srgrimes int rcfirst = 0; /* first message to print (from .rc) */ 1701590Srgrimes int rcback = 0; /* amount to back off of rcfirst */ 17112646Sdg int firstmsg = 0, nextmsg = 0, lastmsg = 0; 1721590Srgrimes int blast = 0; 17337476Sjkh struct stat buf; /* stat to check access of bounds */ 1741590Srgrimes FILE *bounds; 1751590Srgrimes 1761590Srgrimes#ifdef UNBUFFERED 1771590Srgrimes setbuf(stdout, NULL); 1781590Srgrimes#endif 17912809Sache setlocale(LC_ALL, ""); 1801590Srgrimes 1811590Srgrimes time(&t); 18237645Sghelmer setuid(uid = getuid()); 1831590Srgrimes ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); 1841590Srgrimes if (ruptible) 1851590Srgrimes signal(SIGINT, SIG_DFL); 1861590Srgrimes 1871590Srgrimes argc--, argv++; 1881590Srgrimes while (argc > 0) { 1891590Srgrimes if (isdigit(argv[0][0])) { /* starting message # */ 1901590Srgrimes rcfirst = atoi(argv[0]); 1911590Srgrimes } 1921590Srgrimes else if (isdigit(argv[0][1])) { /* backward offset */ 1931590Srgrimes rcback = atoi( &( argv[0][1] ) ); 1941590Srgrimes } 1951590Srgrimes else { 1961590Srgrimes ptr = *argv; 1971590Srgrimes while (*ptr) switch (*ptr++) { 1981590Srgrimes 1991590Srgrimes case '-': 2001590Srgrimes break; 2011590Srgrimes 2021590Srgrimes case 'c': 2031590Srgrimes if (uid != SUPERUSER && uid != DAEMON) { 2041590Srgrimes fprintf(stderr, "Sorry\n"); 2051590Srgrimes exit(1); 2061590Srgrimes } 2071590Srgrimes clean = YES; 2081590Srgrimes break; 2091590Srgrimes 2101590Srgrimes case 'f': /* silently */ 2111590Srgrimes hush = YES; 2121590Srgrimes break; 2131590Srgrimes 2141590Srgrimes case 'h': /* headers only */ 2151590Srgrimes hdrs = YES; 2161590Srgrimes break; 2171590Srgrimes 2181590Srgrimes case 'l': /* local msgs only */ 2191590Srgrimes locomode = YES; 2201590Srgrimes break; 2211590Srgrimes 2221590Srgrimes case 'o': /* option to save last message */ 2231590Srgrimes lastcmd = YES; 2241590Srgrimes break; 2251590Srgrimes 2261590Srgrimes case 'p': /* pipe thru 'more' during long msgs */ 2271590Srgrimes use_pager = YES; 2281590Srgrimes break; 2291590Srgrimes 2301590Srgrimes case 'q': /* query only */ 2311590Srgrimes qopt = YES; 2321590Srgrimes break; 2331590Srgrimes 2341590Srgrimes case 's': /* sending TO msgs */ 2351590Srgrimes send_msg = YES; 2361590Srgrimes break; 2371590Srgrimes 2381590Srgrimes default: 23927751Scharnier usage(); 2401590Srgrimes } 2411590Srgrimes } 2421590Srgrimes argc--, argv++; 2431590Srgrimes } 2441590Srgrimes 2451590Srgrimes /* 2461590Srgrimes * determine current message bounds 2471590Srgrimes */ 24827751Scharnier snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS); 24949061Smjacob 25049061Smjacob /* 25149061Smjacob * Test access rights to the bounds file 25249061Smjacob * This can be a little tricky. if(send_msg), then 25349061Smjacob * we will create it. We assume that if(send_msg), 25449061Smjacob * then you have write permission there. 25549061Smjacob * Else, it better be there, or we bail. 25649061Smjacob */ 25749061Smjacob if (send_msg != YES) { 25849061Smjacob if (stat(fname, &buf) < 0) { 25949061Smjacob if (hush != YES) { 26049061Smjacob err(errno, "%s", fname); 26149061Smjacob } else { 26249061Smjacob exit(1); 26349061Smjacob } 26449061Smjacob } 26549061Smjacob } 2661590Srgrimes bounds = fopen(fname, "r"); 2671590Srgrimes 2681590Srgrimes if (bounds != NULL) { 2691590Srgrimes fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); 2701590Srgrimes fclose(bounds); 2711590Srgrimes blast = lastmsg; /* save upper bound */ 2721590Srgrimes } 2731590Srgrimes 2741590Srgrimes if (clean) 2751590Srgrimes keep = t - (rcback? rcback : NDAYS) DAYS; 2761590Srgrimes 2771590Srgrimes if (clean || bounds == NULL) { /* relocate message bounds */ 27818485Sbde struct dirent *dp; 2791590Srgrimes struct stat stbuf; 2801590Srgrimes bool seenany = NO; 2811590Srgrimes DIR *dirp; 2821590Srgrimes 2831590Srgrimes dirp = opendir(_PATH_MSGS); 28427751Scharnier if (dirp == NULL) 28527751Scharnier err(errno, "%s", _PATH_MSGS); 2861590Srgrimes 2871590Srgrimes firstmsg = 32767; 2881590Srgrimes lastmsg = 0; 2891590Srgrimes 2901590Srgrimes for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ 2911590Srgrimes register char *cp = dp->d_name; 2921590Srgrimes register int i = 0; 2931590Srgrimes 2941590Srgrimes if (dp->d_ino == 0) 2951590Srgrimes continue; 2961590Srgrimes if (dp->d_namlen == 0) 2971590Srgrimes continue; 2981590Srgrimes 2991590Srgrimes if (clean) 30027751Scharnier snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp); 3011590Srgrimes 3021590Srgrimes while (isdigit(*cp)) 3031590Srgrimes i = i * 10 + *cp++ - '0'; 3041590Srgrimes if (*cp) 3051590Srgrimes continue; /* not a message! */ 3061590Srgrimes 3071590Srgrimes if (clean) { 3081590Srgrimes if (stat(inbuf, &stbuf) != 0) 3091590Srgrimes continue; 3101590Srgrimes if (stbuf.st_mtime < keep 3111590Srgrimes && stbuf.st_mode&S_IWRITE) { 3121590Srgrimes unlink(inbuf); 3131590Srgrimes continue; 3141590Srgrimes } 3151590Srgrimes } 3161590Srgrimes 3171590Srgrimes if (i > lastmsg) 3181590Srgrimes lastmsg = i; 3191590Srgrimes if (i < firstmsg) 3201590Srgrimes firstmsg = i; 3211590Srgrimes seenany = YES; 3221590Srgrimes } 3231590Srgrimes closedir(dirp); 3241590Srgrimes 3251590Srgrimes if (!seenany) { 3261590Srgrimes if (blast != 0) /* never lower the upper bound! */ 3271590Srgrimes lastmsg = blast; 3281590Srgrimes firstmsg = lastmsg + 1; 3291590Srgrimes } 3301590Srgrimes else if (blast > lastmsg) 3311590Srgrimes lastmsg = blast; 3321590Srgrimes 3331590Srgrimes if (!send_msg) { 3341590Srgrimes bounds = fopen(fname, "w"); 33527751Scharnier if (bounds == NULL) 33627751Scharnier err(errno, "%s", fname); 3371590Srgrimes chmod(fname, CMODE); 3381590Srgrimes fprintf(bounds, "%d %d\n", firstmsg, lastmsg); 3391590Srgrimes fclose(bounds); 3401590Srgrimes } 3411590Srgrimes } 3421590Srgrimes 3431590Srgrimes if (send_msg) { 3441590Srgrimes /* 3451590Srgrimes * Send mode - place msgs in _PATH_MSGS 3461590Srgrimes */ 3471590Srgrimes bounds = fopen(fname, "w"); 34827751Scharnier if (bounds == NULL) 34927751Scharnier err(errno, "%s", fname); 3501590Srgrimes 3511590Srgrimes nextmsg = lastmsg + 1; 35227751Scharnier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg); 3531590Srgrimes newmsg = fopen(fname, "w"); 35427751Scharnier if (newmsg == NULL) 35527751Scharnier err(errno, "%s", fname); 35612390Sache chmod(fname, CMODE); 3571590Srgrimes 3581590Srgrimes fprintf(bounds, "%d %d\n", firstmsg, nextmsg); 3591590Srgrimes fclose(bounds); 3601590Srgrimes 3611590Srgrimes sending = YES; 3621590Srgrimes if (ruptible) 3631590Srgrimes signal(SIGINT, onintr); 3641590Srgrimes 3651590Srgrimes if (isatty(fileno(stdin))) { 3661590Srgrimes ptr = getpwuid(uid)->pw_name; 3671590Srgrimes printf("Message %d:\nFrom %s %sSubject: ", 3681590Srgrimes nextmsg, ptr, ctime(&t)); 3691590Srgrimes fflush(stdout); 3701590Srgrimes fgets(inbuf, sizeof inbuf, stdin); 3711590Srgrimes putchar('\n'); 3721590Srgrimes fflush(stdout); 3731590Srgrimes fprintf(newmsg, "From %s %sSubject: %s\n", 3741590Srgrimes ptr, ctime(&t), inbuf); 3751590Srgrimes blankline = seensubj = YES; 3761590Srgrimes } 3771590Srgrimes else 3781590Srgrimes blankline = seensubj = NO; 3791590Srgrimes for (;;) { 3801590Srgrimes fgets(inbuf, sizeof inbuf, stdin); 3811590Srgrimes if (feof(stdin) || ferror(stdin)) 3821590Srgrimes break; 3831590Srgrimes blankline = (blankline || (inbuf[0] == '\n')); 3841590Srgrimes seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); 3851590Srgrimes fputs(inbuf, newmsg); 3861590Srgrimes } 3871590Srgrimes#ifdef OBJECT 3881590Srgrimes if (!seensubj) { 3891590Srgrimes printf("NOTICE: Messages should have a Subject field!\n"); 3901590Srgrimes#ifdef REJECT 3911590Srgrimes unlink(fname); 3921590Srgrimes#endif 3931590Srgrimes exit(1); 3941590Srgrimes } 3951590Srgrimes#endif 3961590Srgrimes exit(ferror(stdin)); 3971590Srgrimes } 3981590Srgrimes if (clean) 3991590Srgrimes exit(0); 4001590Srgrimes 4011590Srgrimes /* 4021590Srgrimes * prepare to display messages 4031590Srgrimes */ 4041590Srgrimes totty = (isatty(fileno(stdout)) != 0); 4051590Srgrimes use_pager = use_pager && totty; 4061590Srgrimes 40727751Scharnier snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), MSGSRC); 4081590Srgrimes msgsrc = fopen(fname, "r"); 4091590Srgrimes if (msgsrc) { 4101590Srgrimes newrc = NO; 4111590Srgrimes fscanf(msgsrc, "%d\n", &nextmsg); 4121590Srgrimes fclose(msgsrc); 4131590Srgrimes if (nextmsg > lastmsg+1) { 4141590Srgrimes printf("Warning: bounds have been reset (%d, %d)\n", 4151590Srgrimes firstmsg, lastmsg); 4161590Srgrimes truncate(fname, (off_t)0); 4171590Srgrimes newrc = YES; 4181590Srgrimes } 4191590Srgrimes else if (!rcfirst) 4201590Srgrimes rcfirst = nextmsg - rcback; 4211590Srgrimes } 4221590Srgrimes else 4231590Srgrimes newrc = YES; 4241590Srgrimes msgsrc = fopen(fname, "r+"); 4251590Srgrimes if (msgsrc == NULL) 4261590Srgrimes msgsrc = fopen(fname, "w"); 42727751Scharnier if (msgsrc == NULL) 42827751Scharnier err(errno, "%s", fname); 4291590Srgrimes if (rcfirst) { 4301590Srgrimes if (rcfirst > lastmsg+1) { 4311590Srgrimes printf("Warning: the last message is number %d.\n", 4321590Srgrimes lastmsg); 4331590Srgrimes rcfirst = nextmsg; 4341590Srgrimes } 4351590Srgrimes if (rcfirst > firstmsg) 4361590Srgrimes firstmsg = rcfirst; /* don't set below first msg */ 4371590Srgrimes } 4381590Srgrimes if (newrc) { 4391590Srgrimes nextmsg = firstmsg; 4401590Srgrimes fseek(msgsrc, 0L, 0); 4411590Srgrimes fprintf(msgsrc, "%d\n", nextmsg); 4421590Srgrimes fflush(msgsrc); 4431590Srgrimes } 4441590Srgrimes 4451590Srgrimes#ifdef V7 4461590Srgrimes if (totty) { 4471590Srgrimes struct winsize win; 4481590Srgrimes if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) 4491590Srgrimes Lpp = win.ws_row; 4501590Srgrimes if (Lpp <= 0) { 4511590Srgrimes if (tgetent(inbuf, getenv("TERM")) <= 0 4521590Srgrimes || (Lpp = tgetnum("li")) <= 0) { 4531590Srgrimes Lpp = NLINES; 4541590Srgrimes } 4551590Srgrimes } 4561590Srgrimes } 4571590Srgrimes#endif 4581590Srgrimes Lpp -= 6; /* for headers, etc. */ 4591590Srgrimes 4601590Srgrimes already = NO; 4611590Srgrimes prevmsg = firstmsg; 4621590Srgrimes printing = YES; 4631590Srgrimes if (ruptible) 4641590Srgrimes signal(SIGINT, onintr); 4651590Srgrimes 4661590Srgrimes /* 4671590Srgrimes * Main program loop 4681590Srgrimes */ 4691590Srgrimes for (msg = firstmsg; msg <= lastmsg; msg++) { 4701590Srgrimes 47127751Scharnier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg); 4721590Srgrimes newmsg = fopen(fname, "r"); 4731590Srgrimes if (newmsg == NULL) 4741590Srgrimes continue; 4751590Srgrimes 4761590Srgrimes gfrsub(newmsg); /* get From and Subject fields */ 4771590Srgrimes if (locomode && !local) { 4781590Srgrimes fclose(newmsg); 4791590Srgrimes continue; 4801590Srgrimes } 4811590Srgrimes 4821590Srgrimes if (qopt) { /* This has to be located here */ 4831590Srgrimes printf("There are new messages.\n"); 4841590Srgrimes exit(0); 4851590Srgrimes } 4861590Srgrimes 4871590Srgrimes if (already && !hdrs) 4881590Srgrimes putchar('\n'); 4891590Srgrimes 4901590Srgrimes /* 4911590Srgrimes * Print header 4921590Srgrimes */ 4931590Srgrimes if (totty) 4941590Srgrimes signal(SIGTSTP, onsusp); 4951590Srgrimes (void) setjmp(tstpbuf); 4961590Srgrimes already = YES; 4971590Srgrimes nlines = 2; 4981590Srgrimes if (seenfrom) { 4991590Srgrimes printf("Message %d:\nFrom %s %s", msg, from, date); 5001590Srgrimes nlines++; 5011590Srgrimes } 5021590Srgrimes if (seensubj) { 5031590Srgrimes printf("Subject: %s", subj); 5041590Srgrimes nlines++; 5051590Srgrimes } 5061590Srgrimes else { 5071590Srgrimes if (seenfrom) { 5081590Srgrimes putchar('\n'); 5091590Srgrimes nlines++; 5101590Srgrimes } 5111590Srgrimes while (nlines < 6 5121590Srgrimes && fgets(inbuf, sizeof inbuf, newmsg) 5131590Srgrimes && inbuf[0] != '\n') { 5141590Srgrimes fputs(inbuf, stdout); 5151590Srgrimes nlines++; 5161590Srgrimes } 5171590Srgrimes } 5181590Srgrimes 5191590Srgrimes lct = linecnt(newmsg); 5201590Srgrimes if (lct) 5211590Srgrimes printf("(%d%slines) ", lct, seensubj? " " : " more "); 5221590Srgrimes 5231590Srgrimes if (hdrs) { 5241590Srgrimes printf("\n-----\n"); 5251590Srgrimes fclose(newmsg); 5261590Srgrimes continue; 5271590Srgrimes } 5281590Srgrimes 5291590Srgrimes /* 5301590Srgrimes * Ask user for command 5311590Srgrimes */ 5321590Srgrimes if (totty) 5331590Srgrimes ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); 5341590Srgrimes else 5351590Srgrimes inbuf[0] = 'y'; 5361590Srgrimes if (totty) 5371590Srgrimes signal(SIGTSTP, SIG_DFL); 5381590Srgrimescmnd: 5391590Srgrimes in = inbuf; 5401590Srgrimes switch (*in) { 5411590Srgrimes case 'x': 5421590Srgrimes case 'X': 5431590Srgrimes exit(0); 5441590Srgrimes 5451590Srgrimes case 'q': 5461590Srgrimes case 'Q': 5471590Srgrimes quitit = YES; 5481590Srgrimes printf("--Postponed--\n"); 5491590Srgrimes exit(0); 5501590Srgrimes /* intentional fall-thru */ 5511590Srgrimes case 'n': 5521590Srgrimes case 'N': 5531590Srgrimes if (msg >= nextmsg) sep = "Flushed"; 5541590Srgrimes prevmsg = msg; 5551590Srgrimes break; 5561590Srgrimes 5571590Srgrimes case 'p': 5581590Srgrimes case 'P': 5591590Srgrimes use_pager = (*in++ == 'p'); 5601590Srgrimes /* intentional fallthru */ 5611590Srgrimes case '\n': 5621590Srgrimes case 'y': 5631590Srgrimes default: 5641590Srgrimes if (*in == '-') { 5651590Srgrimes msg = prevmsg-1; 5661590Srgrimes sep = "replay"; 5671590Srgrimes break; 5681590Srgrimes } 5691590Srgrimes if (isdigit(*in)) { 5701590Srgrimes msg = next(in); 5711590Srgrimes sep = in; 5721590Srgrimes break; 5731590Srgrimes } 5741590Srgrimes 5751590Srgrimes prmesg(nlines + lct + (seensubj? 1 : 0)); 5761590Srgrimes prevmsg = msg; 5771590Srgrimes 5781590Srgrimes } 5791590Srgrimes 5801590Srgrimes printf("--%s--\n", sep); 5811590Srgrimes sep = "-"; 5821590Srgrimes if (msg >= nextmsg) { 5831590Srgrimes nextmsg = msg + 1; 5841590Srgrimes fseek(msgsrc, 0L, 0); 5851590Srgrimes fprintf(msgsrc, "%d\n", nextmsg); 5861590Srgrimes fflush(msgsrc); 5871590Srgrimes } 5881590Srgrimes if (newmsg) 5891590Srgrimes fclose(newmsg); 5901590Srgrimes if (quitit) 5911590Srgrimes break; 5921590Srgrimes } 5931590Srgrimes 5941590Srgrimes /* 5951590Srgrimes * Make sure .rc file gets updated 5961590Srgrimes */ 5971590Srgrimes if (--msg >= nextmsg) { 5981590Srgrimes nextmsg = msg + 1; 5991590Srgrimes fseek(msgsrc, 0L, 0); 6001590Srgrimes fprintf(msgsrc, "%d\n", nextmsg); 6011590Srgrimes fflush(msgsrc); 6021590Srgrimes } 6031590Srgrimes if (already && !quitit && lastcmd && totty) { 6041590Srgrimes /* 6051590Srgrimes * save or reply to last message? 6061590Srgrimes */ 6071590Srgrimes msg = prevmsg; 6081590Srgrimes ask(NOMORE); 6091590Srgrimes if (inbuf[0] == '-' || isdigit(inbuf[0])) 6101590Srgrimes goto cmnd; 6111590Srgrimes } 6121590Srgrimes if (!(already || hush || qopt)) 6131590Srgrimes printf("No new messages.\n"); 6141590Srgrimes exit(0); 6151590Srgrimes} 6161590Srgrimes 61727751Scharnierstatic void 61827751Scharnierusage() 61927751Scharnier{ 62027751Scharnier fprintf(stderr, "usage: msgs [fhlopq] [[-]number]\n"); 62127751Scharnier exit(1); 62227751Scharnier} 62327751Scharnier 62427751Scharniervoid 6251590Srgrimesprmesg(length) 6261590Srgrimesint length; 6271590Srgrimes{ 6281590Srgrimes FILE *outf; 62937534Sghelmer char *env_pager; 6301590Srgrimes 6311590Srgrimes if (use_pager && length > Lpp) { 6321590Srgrimes signal(SIGPIPE, SIG_IGN); 6331590Srgrimes signal(SIGQUIT, SIG_IGN); 63437534Sghelmer if ((env_pager = getenv("PAGER")) == NULL) { 63537534Sghelmer snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp); 63637534Sghelmer } else { 63737534Sghelmer snprintf(cmdbuf, sizeof(cmdbuf), env_pager); 63837534Sghelmer } 6391590Srgrimes outf = popen(cmdbuf, "w"); 6401590Srgrimes if (!outf) 6411590Srgrimes outf = stdout; 6421590Srgrimes else 6431590Srgrimes setbuf(outf, (char *)NULL); 6441590Srgrimes } 6451590Srgrimes else 6461590Srgrimes outf = stdout; 6471590Srgrimes 6481590Srgrimes if (seensubj) 6491590Srgrimes putc('\n', outf); 6501590Srgrimes 6511590Srgrimes while (fgets(inbuf, sizeof inbuf, newmsg)) { 6521590Srgrimes fputs(inbuf, outf); 6531590Srgrimes if (ferror(outf)) { 6541590Srgrimes clearerr(outf); 6551590Srgrimes break; 6561590Srgrimes } 6571590Srgrimes } 6581590Srgrimes 6591590Srgrimes if (outf != stdout) { 6601590Srgrimes pclose(outf); 6611590Srgrimes signal(SIGPIPE, SIG_DFL); 6621590Srgrimes signal(SIGQUIT, SIG_DFL); 6631590Srgrimes } 6641590Srgrimes else { 6651590Srgrimes fflush(stdout); 6661590Srgrimes } 6671590Srgrimes 6686591Swollman /* force wait on output */ 6696591Swollman tcdrain(fileno(stdout)); 6701590Srgrimes} 6711590Srgrimes 6721590Srgrimesvoid 67327751Scharnieronintr(unused) 67427751Scharnier int unused; 6751590Srgrimes{ 6761590Srgrimes signal(SIGINT, onintr); 6771590Srgrimes if (mailing) 6781590Srgrimes unlink(fname); 6791590Srgrimes if (sending) { 6801590Srgrimes unlink(fname); 6811590Srgrimes puts("--Killed--"); 6821590Srgrimes exit(1); 6831590Srgrimes } 6841590Srgrimes if (printing) { 6851590Srgrimes putchar('\n'); 6861590Srgrimes if (hdrs) 6871590Srgrimes exit(0); 6881590Srgrimes sep = "Interrupt"; 6891590Srgrimes if (newmsg) 6901590Srgrimes fseek(newmsg, 0L, 2); 6911590Srgrimes intrpflg = YES; 6921590Srgrimes } 6931590Srgrimes} 6941590Srgrimes 6951590Srgrimes/* 6961590Srgrimes * We have just gotten a susp. Suspend and prepare to resume. 6971590Srgrimes */ 6981590Srgrimesvoid 69927751Scharnieronsusp(unused) 70027751Scharnier int unused; 7011590Srgrimes{ 7021590Srgrimes signal(SIGTSTP, SIG_DFL); 7031590Srgrimes sigsetmask(0); 7041590Srgrimes kill(0, SIGTSTP); 7051590Srgrimes signal(SIGTSTP, onsusp); 7061590Srgrimes if (!mailing) 7071590Srgrimes longjmp(tstpbuf, 0); 7081590Srgrimes} 7091590Srgrimes 71027751Scharnierint 7111590Srgrimeslinecnt(f) 7121590SrgrimesFILE *f; 7131590Srgrimes{ 7141590Srgrimes off_t oldpos = ftell(f); 7151590Srgrimes int l = 0; 7161590Srgrimes char lbuf[BUFSIZ]; 7171590Srgrimes 7181590Srgrimes while (fgets(lbuf, sizeof lbuf, f)) 7191590Srgrimes l++; 7201590Srgrimes clearerr(f); 7211590Srgrimes fseek(f, oldpos, 0); 7221590Srgrimes return (l); 7231590Srgrimes} 7241590Srgrimes 72527751Scharnierint 7261590Srgrimesnext(buf) 7271590Srgrimeschar *buf; 7281590Srgrimes{ 7291590Srgrimes int i; 7301590Srgrimes sscanf(buf, "%d", &i); 7311590Srgrimes sprintf(buf, "Goto %d", i); 7321590Srgrimes return(--i); 7331590Srgrimes} 7341590Srgrimes 73527751Scharniervoid 7361590Srgrimesask(prompt) 7371590Srgrimeschar *prompt; 7381590Srgrimes{ 7391590Srgrimes char inch; 74037534Sghelmer int n, cmsg, fd; 7411590Srgrimes off_t oldpos; 7421590Srgrimes FILE *cpfrom, *cpto; 7431590Srgrimes 7441590Srgrimes printf("%s ", prompt); 7451590Srgrimes fflush(stdout); 7461590Srgrimes intrpflg = NO; 7471590Srgrimes (void) fgets(inbuf, sizeof inbuf, stdin); 7481590Srgrimes if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') 7491590Srgrimes inbuf[n - 1] = '\0'; 7501590Srgrimes if (intrpflg) 7511590Srgrimes inbuf[0] = 'x'; 7521590Srgrimes 7531590Srgrimes /* 7541590Srgrimes * Handle 'mail' and 'save' here. 7551590Srgrimes */ 7561590Srgrimes if ((inch = inbuf[0]) == 's' || inch == 'm') { 7571590Srgrimes if (inbuf[1] == '-') 7581590Srgrimes cmsg = prevmsg; 7591590Srgrimes else if (isdigit(inbuf[1])) 7601590Srgrimes cmsg = atoi(&inbuf[1]); 7611590Srgrimes else 7621590Srgrimes cmsg = msg; 76327751Scharnier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg); 7641590Srgrimes 7651590Srgrimes oldpos = ftell(newmsg); 7661590Srgrimes 7671590Srgrimes cpfrom = fopen(fname, "r"); 7681590Srgrimes if (!cpfrom) { 7691590Srgrimes printf("Message %d not found\n", cmsg); 7701590Srgrimes ask (prompt); 7711590Srgrimes return; 7721590Srgrimes } 7731590Srgrimes 7741590Srgrimes if (inch == 's') { 7751590Srgrimes in = nxtfld(inbuf); 7761590Srgrimes if (*in) { 7771590Srgrimes for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ 7781590Srgrimes fname[n] = in[n]; 7791590Srgrimes } 7801590Srgrimes fname[n] = NULL; 7811590Srgrimes } 7821590Srgrimes else 7831590Srgrimes strcpy(fname, "Messages"); 78437534Sghelmer fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND); 7851590Srgrimes } 7861590Srgrimes else { 7871590Srgrimes strcpy(fname, _PATH_TMP); 78837534Sghelmer fd = mkstemp(fname); 78937534Sghelmer if (fd != -1) { 79037534Sghelmer snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, 79137534Sghelmer fname); 79237534Sghelmer mailing = YES; 79337534Sghelmer } 7941590Srgrimes } 79537534Sghelmer if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) { 79637534Sghelmer if (fd != -1) 79737534Sghelmer close(fd); 79827751Scharnier warn("%s", fname); 7991590Srgrimes mailing = NO; 8001590Srgrimes fseek(newmsg, oldpos, 0); 8011590Srgrimes ask(prompt); 8021590Srgrimes return; 8031590Srgrimes } 8041590Srgrimes 80527751Scharnier while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom))) 8061590Srgrimes fwrite(inbuf, 1, n, cpto); 8071590Srgrimes 8081590Srgrimes fclose(cpfrom); 8091590Srgrimes fclose(cpto); 8101590Srgrimes fseek(newmsg, oldpos, 0); /* reposition current message */ 8111590Srgrimes if (inch == 's') 8121590Srgrimes printf("Message %d saved in \"%s\"\n", cmsg, fname); 8131590Srgrimes else { 8141590Srgrimes system(cmdbuf); 8151590Srgrimes unlink(fname); 8161590Srgrimes mailing = NO; 8171590Srgrimes } 8181590Srgrimes ask(prompt); 8191590Srgrimes } 8201590Srgrimes} 8211590Srgrimes 82227751Scharniervoid 8231590Srgrimesgfrsub(infile) 8241590SrgrimesFILE *infile; 8251590Srgrimes{ 8261590Srgrimes off_t frompos; 82737534Sghelmer int count; 8281590Srgrimes 8291590Srgrimes seensubj = seenfrom = NO; 8301590Srgrimes local = YES; 8311590Srgrimes subj[0] = from[0] = date[0] = NULL; 8321590Srgrimes 8331590Srgrimes /* 8341590Srgrimes * Is this a normal message? 8351590Srgrimes */ 8361590Srgrimes if (fgets(inbuf, sizeof inbuf, infile)) { 8371590Srgrimes if (strncmp(inbuf, "From", 4)==0) { 8381590Srgrimes /* 8391590Srgrimes * expected form starts with From 8401590Srgrimes */ 8411590Srgrimes seenfrom = YES; 8421590Srgrimes frompos = ftell(infile); 8431590Srgrimes ptr = from; 8441590Srgrimes in = nxtfld(inbuf); 84537534Sghelmer if (*in) { 84637534Sghelmer count = sizeof(from) - 1; 84737534Sghelmer while (*in && *in > ' ' && count-- > 0) { 84837534Sghelmer if (*in == ':' || *in == '@' || 84937534Sghelmer *in == '!') 85037534Sghelmer local = NO; 85137534Sghelmer *ptr++ = *in++; 85237534Sghelmer } 8531590Srgrimes } 8541590Srgrimes *ptr = NULL; 8551590Srgrimes if (*(in = nxtfld(in))) 8561590Srgrimes strncpy(date, in, sizeof date); 8571590Srgrimes else { 8581590Srgrimes date[0] = '\n'; 8591590Srgrimes date[1] = NULL; 8601590Srgrimes } 8611590Srgrimes } 8621590Srgrimes else { 8631590Srgrimes /* 8641590Srgrimes * not the expected form 8651590Srgrimes */ 8661590Srgrimes fseek(infile, 0L, 0); 8671590Srgrimes return; 8681590Srgrimes } 8691590Srgrimes } 8701590Srgrimes else 8711590Srgrimes /* 8721590Srgrimes * empty file ? 8731590Srgrimes */ 8741590Srgrimes return; 8751590Srgrimes 8761590Srgrimes /* 8771590Srgrimes * look for Subject line until EOF or a blank line 8781590Srgrimes */ 8791590Srgrimes while (fgets(inbuf, sizeof inbuf, infile) 8801590Srgrimes && !(blankline = (inbuf[0] == '\n'))) { 8811590Srgrimes /* 8821590Srgrimes * extract Subject line 8831590Srgrimes */ 8841590Srgrimes if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { 8851590Srgrimes seensubj = YES; 8861590Srgrimes frompos = ftell(infile); 8871590Srgrimes strncpy(subj, nxtfld(inbuf), sizeof subj); 8881590Srgrimes } 8891590Srgrimes } 8901590Srgrimes if (!blankline) 8911590Srgrimes /* 8921590Srgrimes * ran into EOF 8931590Srgrimes */ 8941590Srgrimes fseek(infile, frompos, 0); 8951590Srgrimes 8961590Srgrimes if (!seensubj) 8971590Srgrimes /* 8981590Srgrimes * for possible use with Mail 8991590Srgrimes */ 9001590Srgrimes strncpy(subj, "(No Subject)\n", sizeof subj); 9011590Srgrimes} 9021590Srgrimes 9031590Srgrimeschar * 9041590Srgrimesnxtfld(s) 90512809Sacheunsigned char *s; 9061590Srgrimes{ 90712809Sache if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */ 90812809Sache if (*s) while (*s && isspace(*s)) s++; /* find start of next field */ 9091590Srgrimes return (s); 9101590Srgrimes} 911