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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127751Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 3694992Sbde#if 0 371590Srgrimes#ifndef lint 3827751Scharnierstatic char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95"; 3994992Sbde#endif /* not lint */ 4027751Scharnier#endif 411590Srgrimes 4294504Scharnier#include <sys/cdefs.h> 4394504Scharnier__FBSDID("$FreeBSD$"); 4494504Scharnier 451590Srgrimes/* 461590Srgrimes * msgs - a user bulletin board program 471590Srgrimes * 481590Srgrimes * usage: 491590Srgrimes * msgs [fhlopq] [[-]number] to read messages 501590Srgrimes * msgs -s to place messages 511590Srgrimes * msgs -c [-days] to clean up the bulletin board 521590Srgrimes * 531590Srgrimes * prompt commands are: 541590Srgrimes * y print message 551590Srgrimes * n flush message, go to next message 561590Srgrimes * q flush message, quit 571590Srgrimes * p print message, turn on 'pipe thru more' mode 581590Srgrimes * P print message, turn off 'pipe thru more' mode 591590Srgrimes * - reprint last message 601590Srgrimes * s[-][<num>] [<filename>] save message 611590Srgrimes * m[-][<num>] mail with message in temp mbox 621590Srgrimes * x exit without flushing this message 631590Srgrimes * <num> print message number <num> 641590Srgrimes */ 651590Srgrimes 661590Srgrimes#define V7 /* will look for TERM in the environment */ 671590Srgrimes#define OBJECT /* will object to messages without Subjects */ 688382Srgrimes/* #define REJECT */ /* will reject messages without Subjects 691590Srgrimes (OBJECT must be defined also) */ 708382Srgrimes/* #define UNBUFFERED *//* use unbuffered output */ 711590Srgrimes 721590Srgrimes#include <sys/param.h> 731590Srgrimes#include <sys/stat.h> 741590Srgrimes#include <ctype.h> 7518485Sbde#include <dirent.h> 7627751Scharnier#include <err.h> 771590Srgrimes#include <errno.h> 7837534Sghelmer#include <fcntl.h> 7912809Sache#include <locale.h> 801590Srgrimes#include <pwd.h> 811590Srgrimes#include <setjmp.h> 8227751Scharnier#include <termcap.h> 836591Swollman#include <termios.h> 841590Srgrimes#include <signal.h> 851590Srgrimes#include <stdio.h> 861590Srgrimes#include <stdlib.h> 871590Srgrimes#include <string.h> 881590Srgrimes#include <time.h> 891590Srgrimes#include <unistd.h> 901590Srgrimes#include "pathnames.h" 911590Srgrimes 9212390Sache#define CMODE 0644 /* bounds file creation mode */ 931590Srgrimes#define NO 0 941590Srgrimes#define YES 1 951590Srgrimes#define SUPERUSER 0 /* superuser uid */ 961590Srgrimes#define DAEMON 1 /* daemon uid */ 971590Srgrimes#define NLINES 24 /* default number of lines/crt screen */ 981590Srgrimes#define NDAYS 21 /* default keep time for messages */ 991590Srgrimes#define DAYS *24*60*60 /* seconds/day */ 1001590Srgrimes#define MSGSRC ".msgsrc" /* user's rc file */ 1011590Srgrimes#define BOUNDS "bounds" /* message bounds file */ 1021590Srgrimes#define NEXT "Next message? [yq]" 1031590Srgrimes#define MORE "More? [ynq]" 1041590Srgrimes#define NOMORE "(No more) [q] ?" 1051590Srgrimes 1061590Srgrimestypedef char bool; 1071590Srgrimes 108241737Sedstatic FILE *msgsrc; 109241737Sedstatic FILE *newmsg; 110241737Sedstatic const char *sep = "-"; 111241737Sedstatic char inbuf[BUFSIZ]; 112241737Sedstatic char fname[MAXPATHLEN]; 113241737Sedstatic char cmdbuf[MAXPATHLEN + MAXPATHLEN]; 114241737Sedstatic char subj[128]; 115241737Sedstatic char from[128]; 116241737Sedstatic char date[128]; 117241737Sedstatic char *ptr; 118241737Sedstatic char *in; 119241737Sedstatic bool local; 120241737Sedstatic bool ruptible; 121241737Sedstatic bool totty; 122241737Sedstatic bool seenfrom; 123241737Sedstatic bool seensubj; 124241737Sedstatic bool blankline; 125241737Sedstatic bool printing = NO; 126241737Sedstatic bool mailing = NO; 127241737Sedstatic bool quitit = NO; 128241737Sedstatic bool sending = NO; 129241737Sedstatic bool intrpflg = NO; 130241737Sedstatic uid_t uid; 131241737Sedstatic int msg; 132241737Sedstatic int prevmsg; 133241737Sedstatic int lct; 134241737Sedstatic int nlines; 135241737Sedstatic int Lpp = 0; 136241737Sedstatic time_t t; 137241737Sedstatic time_t keep; 1381590Srgrimes 1391590Srgrimes/* option initialization */ 140241737Sedstatic bool hdrs = NO; 141241737Sedstatic bool qopt = NO; 142241737Sedstatic bool hush = NO; 143241737Sedstatic bool send_msg = NO; 144241737Sedstatic bool locomode = NO; 145241737Sedstatic bool use_pager = NO; 146241737Sedstatic bool clean = NO; 147241737Sedstatic bool lastcmd = NO; 148241737Sedstatic jmp_buf tstpbuf; 1491590Srgrimes 150140389Sdelphijstatic void ask(const char *); 151140389Sdelphijstatic void gfrsub(FILE *); 152140389Sdelphijstatic int linecnt(FILE *); 153140389Sdelphijstatic int next(char *); 154140389Sdelphijstatic char *nxtfld(char *); 155140389Sdelphijstatic void onsusp(int); 156140389Sdelphijstatic void onintr(int); 157140389Sdelphijstatic void prmesg(int); 158241737Sedstatic void usage(void); 15927751Scharnier 16027751Scharnierint 161102944Sdwmalonemain(int argc, char *argv[]) 1621590Srgrimes{ 1631590Srgrimes bool newrc, already; 1641590Srgrimes int rcfirst = 0; /* first message to print (from .rc) */ 1651590Srgrimes int rcback = 0; /* amount to back off of rcfirst */ 16612646Sdg int firstmsg = 0, nextmsg = 0, lastmsg = 0; 1671590Srgrimes int blast = 0; 16837476Sjkh struct stat buf; /* stat to check access of bounds */ 1691590Srgrimes FILE *bounds; 170173169Skevlo char *cp; 1711590Srgrimes 1721590Srgrimes#ifdef UNBUFFERED 1731590Srgrimes setbuf(stdout, NULL); 1741590Srgrimes#endif 17512809Sache setlocale(LC_ALL, ""); 1761590Srgrimes 1771590Srgrimes time(&t); 178241848Seadler if (setuid(uid = getuid()) != 0) 179241848Seadler err(1, "setuid failed"); 1801590Srgrimes ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); 1811590Srgrimes if (ruptible) 1821590Srgrimes signal(SIGINT, SIG_DFL); 1831590Srgrimes 1841590Srgrimes argc--, argv++; 1851590Srgrimes while (argc > 0) { 1861590Srgrimes if (isdigit(argv[0][0])) { /* starting message # */ 1871590Srgrimes rcfirst = atoi(argv[0]); 1881590Srgrimes } 1891590Srgrimes else if (isdigit(argv[0][1])) { /* backward offset */ 1901590Srgrimes rcback = atoi( &( argv[0][1] ) ); 1911590Srgrimes } 1921590Srgrimes else { 1931590Srgrimes ptr = *argv; 1941590Srgrimes while (*ptr) switch (*ptr++) { 1951590Srgrimes 1961590Srgrimes case '-': 1971590Srgrimes break; 1981590Srgrimes 1991590Srgrimes case 'c': 20094504Scharnier if (uid != SUPERUSER && uid != DAEMON) 20194504Scharnier errx(1, 20294504Scharnier "only the super-user can use the c flag"); 2031590Srgrimes clean = YES; 2041590Srgrimes break; 2051590Srgrimes 2061590Srgrimes case 'f': /* silently */ 2071590Srgrimes hush = YES; 2081590Srgrimes break; 2091590Srgrimes 2101590Srgrimes case 'h': /* headers only */ 2111590Srgrimes hdrs = YES; 2121590Srgrimes break; 2131590Srgrimes 2141590Srgrimes case 'l': /* local msgs only */ 2151590Srgrimes locomode = YES; 2161590Srgrimes break; 2171590Srgrimes 2181590Srgrimes case 'o': /* option to save last message */ 2191590Srgrimes lastcmd = YES; 2201590Srgrimes break; 2211590Srgrimes 2221590Srgrimes case 'p': /* pipe thru 'more' during long msgs */ 2231590Srgrimes use_pager = YES; 2241590Srgrimes break; 2251590Srgrimes 2261590Srgrimes case 'q': /* query only */ 2271590Srgrimes qopt = YES; 2281590Srgrimes break; 2291590Srgrimes 2301590Srgrimes case 's': /* sending TO msgs */ 2311590Srgrimes send_msg = YES; 2321590Srgrimes break; 2331590Srgrimes 2341590Srgrimes default: 23527751Scharnier usage(); 2361590Srgrimes } 2371590Srgrimes } 2381590Srgrimes argc--, argv++; 2391590Srgrimes } 2401590Srgrimes 2411590Srgrimes /* 2421590Srgrimes * determine current message bounds 2431590Srgrimes */ 24427751Scharnier snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS); 24549061Smjacob 24649061Smjacob /* 24749061Smjacob * Test access rights to the bounds file 24849061Smjacob * This can be a little tricky. if(send_msg), then 24949061Smjacob * we will create it. We assume that if(send_msg), 25049061Smjacob * then you have write permission there. 25149061Smjacob * Else, it better be there, or we bail. 25249061Smjacob */ 25349061Smjacob if (send_msg != YES) { 25449061Smjacob if (stat(fname, &buf) < 0) { 25549061Smjacob if (hush != YES) { 25649061Smjacob err(errno, "%s", fname); 25749061Smjacob } else { 25849061Smjacob exit(1); 25949061Smjacob } 26049061Smjacob } 26149061Smjacob } 2621590Srgrimes bounds = fopen(fname, "r"); 2631590Srgrimes 2641590Srgrimes if (bounds != NULL) { 2651590Srgrimes fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); 2661590Srgrimes fclose(bounds); 2671590Srgrimes blast = lastmsg; /* save upper bound */ 2681590Srgrimes } 2691590Srgrimes 2701590Srgrimes if (clean) 2711590Srgrimes keep = t - (rcback? rcback : NDAYS) DAYS; 2721590Srgrimes 2731590Srgrimes if (clean || bounds == NULL) { /* relocate message bounds */ 27418485Sbde struct dirent *dp; 2751590Srgrimes struct stat stbuf; 2761590Srgrimes bool seenany = NO; 2771590Srgrimes DIR *dirp; 2781590Srgrimes 2791590Srgrimes dirp = opendir(_PATH_MSGS); 28027751Scharnier if (dirp == NULL) 28127751Scharnier err(errno, "%s", _PATH_MSGS); 2821590Srgrimes 2831590Srgrimes firstmsg = 32767; 2841590Srgrimes lastmsg = 0; 2851590Srgrimes 2861590Srgrimes for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ 287173169Skevlo cp = dp->d_name; 288102944Sdwmalone int i = 0; 2891590Srgrimes 2901590Srgrimes if (dp->d_ino == 0) 2911590Srgrimes continue; 2921590Srgrimes if (dp->d_namlen == 0) 2931590Srgrimes continue; 2941590Srgrimes 2951590Srgrimes if (clean) 29627751Scharnier snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp); 2971590Srgrimes 2981590Srgrimes while (isdigit(*cp)) 2991590Srgrimes i = i * 10 + *cp++ - '0'; 3001590Srgrimes if (*cp) 3011590Srgrimes continue; /* not a message! */ 3021590Srgrimes 3031590Srgrimes if (clean) { 3041590Srgrimes if (stat(inbuf, &stbuf) != 0) 3051590Srgrimes continue; 3061590Srgrimes if (stbuf.st_mtime < keep 3071590Srgrimes && stbuf.st_mode&S_IWRITE) { 3081590Srgrimes unlink(inbuf); 3091590Srgrimes continue; 3101590Srgrimes } 3111590Srgrimes } 3121590Srgrimes 3131590Srgrimes if (i > lastmsg) 3141590Srgrimes lastmsg = i; 3151590Srgrimes if (i < firstmsg) 3161590Srgrimes firstmsg = i; 3171590Srgrimes seenany = YES; 3181590Srgrimes } 3191590Srgrimes closedir(dirp); 3201590Srgrimes 3211590Srgrimes if (!seenany) { 3221590Srgrimes if (blast != 0) /* never lower the upper bound! */ 3231590Srgrimes lastmsg = blast; 3241590Srgrimes firstmsg = lastmsg + 1; 3251590Srgrimes } 3261590Srgrimes else if (blast > lastmsg) 3271590Srgrimes lastmsg = blast; 3281590Srgrimes 3291590Srgrimes if (!send_msg) { 3301590Srgrimes bounds = fopen(fname, "w"); 33127751Scharnier if (bounds == NULL) 33227751Scharnier err(errno, "%s", fname); 3331590Srgrimes chmod(fname, CMODE); 3341590Srgrimes fprintf(bounds, "%d %d\n", firstmsg, lastmsg); 3351590Srgrimes fclose(bounds); 3361590Srgrimes } 3371590Srgrimes } 3381590Srgrimes 3391590Srgrimes if (send_msg) { 3401590Srgrimes /* 3411590Srgrimes * Send mode - place msgs in _PATH_MSGS 3421590Srgrimes */ 3431590Srgrimes bounds = fopen(fname, "w"); 34427751Scharnier if (bounds == NULL) 34527751Scharnier err(errno, "%s", fname); 3461590Srgrimes 3471590Srgrimes nextmsg = lastmsg + 1; 34827751Scharnier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg); 3491590Srgrimes newmsg = fopen(fname, "w"); 35027751Scharnier if (newmsg == NULL) 35127751Scharnier err(errno, "%s", fname); 35212390Sache chmod(fname, CMODE); 3531590Srgrimes 3541590Srgrimes fprintf(bounds, "%d %d\n", firstmsg, nextmsg); 3551590Srgrimes fclose(bounds); 3561590Srgrimes 3571590Srgrimes sending = YES; 3581590Srgrimes if (ruptible) 3591590Srgrimes signal(SIGINT, onintr); 3601590Srgrimes 3611590Srgrimes if (isatty(fileno(stdin))) { 3621590Srgrimes ptr = getpwuid(uid)->pw_name; 3631590Srgrimes printf("Message %d:\nFrom %s %sSubject: ", 3641590Srgrimes nextmsg, ptr, ctime(&t)); 3651590Srgrimes fflush(stdout); 3661590Srgrimes fgets(inbuf, sizeof inbuf, stdin); 3671590Srgrimes putchar('\n'); 3681590Srgrimes fflush(stdout); 3691590Srgrimes fprintf(newmsg, "From %s %sSubject: %s\n", 3701590Srgrimes ptr, ctime(&t), inbuf); 3711590Srgrimes blankline = seensubj = YES; 3721590Srgrimes } 3731590Srgrimes else 3741590Srgrimes blankline = seensubj = NO; 3751590Srgrimes for (;;) { 3761590Srgrimes fgets(inbuf, sizeof inbuf, stdin); 3771590Srgrimes if (feof(stdin) || ferror(stdin)) 3781590Srgrimes break; 3791590Srgrimes blankline = (blankline || (inbuf[0] == '\n')); 3801590Srgrimes seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); 3811590Srgrimes fputs(inbuf, newmsg); 3821590Srgrimes } 3831590Srgrimes#ifdef OBJECT 3841590Srgrimes if (!seensubj) { 3851590Srgrimes printf("NOTICE: Messages should have a Subject field!\n"); 3861590Srgrimes#ifdef REJECT 3871590Srgrimes unlink(fname); 3881590Srgrimes#endif 3891590Srgrimes exit(1); 3901590Srgrimes } 3911590Srgrimes#endif 3921590Srgrimes exit(ferror(stdin)); 3931590Srgrimes } 3941590Srgrimes if (clean) 3951590Srgrimes exit(0); 3961590Srgrimes 3971590Srgrimes /* 3981590Srgrimes * prepare to display messages 3991590Srgrimes */ 4001590Srgrimes totty = (isatty(fileno(stdout)) != 0); 4011590Srgrimes use_pager = use_pager && totty; 4021590Srgrimes 403173169Skevlo if ((cp = getenv("HOME")) == NULL || *cp == '\0') { 404173169Skevlo fprintf(stderr, "Error, no home directory!\n"); 405173169Skevlo exit(1); 406173169Skevlo } 407173169Skevlo snprintf(fname, sizeof(fname), "%s/%s", cp, 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; 44082846Sache rewind(msgsrc); 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 45294991Sbde || (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) 521110478Smike printf("(%d%sline%s) ", lct, seensubj? " " : " more ", 522110478Smike (lct == 1) ? "" : "s"); 5231590Srgrimes 5241590Srgrimes if (hdrs) { 5251590Srgrimes printf("\n-----\n"); 5261590Srgrimes fclose(newmsg); 5271590Srgrimes continue; 5281590Srgrimes } 5291590Srgrimes 5301590Srgrimes /* 5311590Srgrimes * Ask user for command 5321590Srgrimes */ 5331590Srgrimes if (totty) 5341590Srgrimes ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); 5351590Srgrimes else 5361590Srgrimes inbuf[0] = 'y'; 5371590Srgrimes if (totty) 5381590Srgrimes signal(SIGTSTP, SIG_DFL); 5391590Srgrimescmnd: 5401590Srgrimes in = inbuf; 5411590Srgrimes switch (*in) { 5421590Srgrimes case 'x': 54394504Scharnier /* FALLTHROUGH */ 5441590Srgrimes case 'X': 5451590Srgrimes exit(0); 54694504Scharnier /* NOTREACHED */ 54794992Sbde 5481590Srgrimes case 'q': 54994504Scharnier /* FALLTHROUGH */ 5501590Srgrimes case 'Q': 5511590Srgrimes quitit = YES; 5521590Srgrimes printf("--Postponed--\n"); 5531590Srgrimes exit(0); 55494504Scharnier /* NOTREACHED */ 55594992Sbde 5561590Srgrimes case 'n': 55794504Scharnier /* FALLTHROUGH */ 5581590Srgrimes case 'N': 5591590Srgrimes if (msg >= nextmsg) sep = "Flushed"; 5601590Srgrimes prevmsg = msg; 5611590Srgrimes break; 5621590Srgrimes 5631590Srgrimes case 'p': 56494504Scharnier /* FALLTHROUGH */ 5651590Srgrimes case 'P': 5661590Srgrimes use_pager = (*in++ == 'p'); 56794504Scharnier /* FALLTHROUGH */ 5681590Srgrimes case '\n': 56994504Scharnier /* FALLTHROUGH */ 5701590Srgrimes case 'y': 5711590Srgrimes default: 5721590Srgrimes if (*in == '-') { 5731590Srgrimes msg = prevmsg-1; 5741590Srgrimes sep = "replay"; 5751590Srgrimes break; 5761590Srgrimes } 5771590Srgrimes if (isdigit(*in)) { 5781590Srgrimes msg = next(in); 5791590Srgrimes sep = in; 5801590Srgrimes break; 5811590Srgrimes } 5821590Srgrimes 5831590Srgrimes prmesg(nlines + lct + (seensubj? 1 : 0)); 5841590Srgrimes prevmsg = msg; 5851590Srgrimes 5861590Srgrimes } 5871590Srgrimes 5881590Srgrimes printf("--%s--\n", sep); 5891590Srgrimes sep = "-"; 5901590Srgrimes if (msg >= nextmsg) { 5911590Srgrimes nextmsg = msg + 1; 59282846Sache rewind(msgsrc); 5931590Srgrimes fprintf(msgsrc, "%d\n", nextmsg); 5941590Srgrimes fflush(msgsrc); 5951590Srgrimes } 5961590Srgrimes if (newmsg) 5971590Srgrimes fclose(newmsg); 5981590Srgrimes if (quitit) 5991590Srgrimes break; 6001590Srgrimes } 6011590Srgrimes 6021590Srgrimes /* 6031590Srgrimes * Make sure .rc file gets updated 6041590Srgrimes */ 6051590Srgrimes if (--msg >= nextmsg) { 6061590Srgrimes nextmsg = msg + 1; 60782846Sache rewind(msgsrc); 6081590Srgrimes fprintf(msgsrc, "%d\n", nextmsg); 6091590Srgrimes fflush(msgsrc); 6101590Srgrimes } 6111590Srgrimes if (already && !quitit && lastcmd && totty) { 6121590Srgrimes /* 6131590Srgrimes * save or reply to last message? 6141590Srgrimes */ 6151590Srgrimes msg = prevmsg; 6161590Srgrimes ask(NOMORE); 6171590Srgrimes if (inbuf[0] == '-' || isdigit(inbuf[0])) 6181590Srgrimes goto cmnd; 6191590Srgrimes } 6201590Srgrimes if (!(already || hush || qopt)) 6211590Srgrimes printf("No new messages.\n"); 6221590Srgrimes exit(0); 62394504Scharnier /* NOTREACHED */ 6241590Srgrimes} 6251590Srgrimes 62627751Scharnierstatic void 627102944Sdwmaloneusage(void) 62827751Scharnier{ 62927751Scharnier fprintf(stderr, "usage: msgs [fhlopq] [[-]number]\n"); 63027751Scharnier exit(1); 63127751Scharnier} 63227751Scharnier 633140389Sdelphijstatic void 634102944Sdwmaloneprmesg(int length) 6351590Srgrimes{ 6361590Srgrimes FILE *outf; 63737534Sghelmer char *env_pager; 6381590Srgrimes 6391590Srgrimes if (use_pager && length > Lpp) { 6401590Srgrimes signal(SIGPIPE, SIG_IGN); 6411590Srgrimes signal(SIGQUIT, SIG_IGN); 64237534Sghelmer if ((env_pager = getenv("PAGER")) == NULL) { 64337534Sghelmer snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp); 64437534Sghelmer } else { 64562726Skris snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager); 64637534Sghelmer } 6471590Srgrimes outf = popen(cmdbuf, "w"); 6481590Srgrimes if (!outf) 6491590Srgrimes outf = stdout; 6501590Srgrimes else 6511590Srgrimes setbuf(outf, (char *)NULL); 6521590Srgrimes } 6531590Srgrimes else 6541590Srgrimes outf = stdout; 6551590Srgrimes 6561590Srgrimes if (seensubj) 6571590Srgrimes putc('\n', outf); 6581590Srgrimes 6591590Srgrimes while (fgets(inbuf, sizeof inbuf, newmsg)) { 6601590Srgrimes fputs(inbuf, outf); 6611590Srgrimes if (ferror(outf)) { 6621590Srgrimes clearerr(outf); 6631590Srgrimes break; 6641590Srgrimes } 6651590Srgrimes } 6661590Srgrimes 6671590Srgrimes if (outf != stdout) { 6681590Srgrimes pclose(outf); 6691590Srgrimes signal(SIGPIPE, SIG_DFL); 6701590Srgrimes signal(SIGQUIT, SIG_DFL); 6711590Srgrimes } 6721590Srgrimes else { 6731590Srgrimes fflush(stdout); 6741590Srgrimes } 6751590Srgrimes 6766591Swollman /* force wait on output */ 6776591Swollman tcdrain(fileno(stdout)); 6781590Srgrimes} 6791590Srgrimes 680140389Sdelphijstatic void 681102944Sdwmaloneonintr(int unused __unused) 6821590Srgrimes{ 6831590Srgrimes signal(SIGINT, onintr); 6841590Srgrimes if (mailing) 6851590Srgrimes unlink(fname); 6861590Srgrimes if (sending) { 6871590Srgrimes unlink(fname); 6881590Srgrimes puts("--Killed--"); 6891590Srgrimes exit(1); 6901590Srgrimes } 6911590Srgrimes if (printing) { 6921590Srgrimes putchar('\n'); 6931590Srgrimes if (hdrs) 6941590Srgrimes exit(0); 6951590Srgrimes sep = "Interrupt"; 6961590Srgrimes if (newmsg) 69782846Sache fseeko(newmsg, (off_t)0, SEEK_END); 6981590Srgrimes intrpflg = YES; 6991590Srgrimes } 7001590Srgrimes} 7011590Srgrimes 7021590Srgrimes/* 7031590Srgrimes * We have just gotten a susp. Suspend and prepare to resume. 7041590Srgrimes */ 705140389Sdelphijstatic void 706102944Sdwmaloneonsusp(int unused __unused) 7071590Srgrimes{ 7081590Srgrimes signal(SIGTSTP, SIG_DFL); 7091590Srgrimes sigsetmask(0); 7101590Srgrimes kill(0, SIGTSTP); 7111590Srgrimes signal(SIGTSTP, onsusp); 7121590Srgrimes if (!mailing) 7131590Srgrimes longjmp(tstpbuf, 0); 7141590Srgrimes} 7151590Srgrimes 716140389Sdelphijstatic int 717102944Sdwmalonelinecnt(FILE *f) 7181590Srgrimes{ 71982846Sache off_t oldpos = ftello(f); 7201590Srgrimes int l = 0; 7211590Srgrimes char lbuf[BUFSIZ]; 7221590Srgrimes 7231590Srgrimes while (fgets(lbuf, sizeof lbuf, f)) 7241590Srgrimes l++; 7251590Srgrimes clearerr(f); 72682846Sache fseeko(f, oldpos, SEEK_SET); 7271590Srgrimes return (l); 7281590Srgrimes} 7291590Srgrimes 730140389Sdelphijstatic int 731102944Sdwmalonenext(char *buf) 7321590Srgrimes{ 7331590Srgrimes int i; 7341590Srgrimes sscanf(buf, "%d", &i); 7351590Srgrimes sprintf(buf, "Goto %d", i); 7361590Srgrimes return(--i); 7371590Srgrimes} 7381590Srgrimes 739140389Sdelphijstatic void 740102944Sdwmaloneask(const char *prompt) 7411590Srgrimes{ 7421590Srgrimes char inch; 74337534Sghelmer int n, cmsg, fd; 7441590Srgrimes off_t oldpos; 7451590Srgrimes FILE *cpfrom, *cpto; 7461590Srgrimes 7471590Srgrimes printf("%s ", prompt); 7481590Srgrimes fflush(stdout); 7491590Srgrimes intrpflg = NO; 7501590Srgrimes (void) fgets(inbuf, sizeof inbuf, stdin); 7511590Srgrimes if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') 7521590Srgrimes inbuf[n - 1] = '\0'; 7531590Srgrimes if (intrpflg) 7541590Srgrimes inbuf[0] = 'x'; 7551590Srgrimes 7561590Srgrimes /* 7571590Srgrimes * Handle 'mail' and 'save' here. 7581590Srgrimes */ 7591590Srgrimes if ((inch = inbuf[0]) == 's' || inch == 'm') { 7601590Srgrimes if (inbuf[1] == '-') 7611590Srgrimes cmsg = prevmsg; 7621590Srgrimes else if (isdigit(inbuf[1])) 7631590Srgrimes cmsg = atoi(&inbuf[1]); 7641590Srgrimes else 7651590Srgrimes cmsg = msg; 76627751Scharnier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg); 7671590Srgrimes 76882846Sache oldpos = ftello(newmsg); 7691590Srgrimes 7701590Srgrimes cpfrom = fopen(fname, "r"); 7711590Srgrimes if (!cpfrom) { 7721590Srgrimes printf("Message %d not found\n", cmsg); 7731590Srgrimes ask (prompt); 7741590Srgrimes return; 7751590Srgrimes } 7761590Srgrimes 7771590Srgrimes if (inch == 's') { 7781590Srgrimes in = nxtfld(inbuf); 7791590Srgrimes if (*in) { 7801590Srgrimes for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ 7811590Srgrimes fname[n] = in[n]; 7821590Srgrimes } 783126838Sbde fname[n] = '\0'; 7841590Srgrimes } 7851590Srgrimes else 7861590Srgrimes strcpy(fname, "Messages"); 78737534Sghelmer fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND); 7881590Srgrimes } 7891590Srgrimes else { 7901590Srgrimes strcpy(fname, _PATH_TMP); 79137534Sghelmer fd = mkstemp(fname); 79237534Sghelmer if (fd != -1) { 79337534Sghelmer snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, 79437534Sghelmer fname); 79537534Sghelmer mailing = YES; 79637534Sghelmer } 7971590Srgrimes } 79837534Sghelmer if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) { 79937534Sghelmer if (fd != -1) 80037534Sghelmer close(fd); 80127751Scharnier warn("%s", fname); 8021590Srgrimes mailing = NO; 80382846Sache fseeko(newmsg, oldpos, SEEK_SET); 8041590Srgrimes ask(prompt); 8051590Srgrimes return; 8061590Srgrimes } 8071590Srgrimes 80827751Scharnier while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom))) 8091590Srgrimes fwrite(inbuf, 1, n, cpto); 8101590Srgrimes 8111590Srgrimes fclose(cpfrom); 8121590Srgrimes fclose(cpto); 81382846Sache fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */ 8141590Srgrimes if (inch == 's') 8151590Srgrimes printf("Message %d saved in \"%s\"\n", cmsg, fname); 8161590Srgrimes else { 8171590Srgrimes system(cmdbuf); 8181590Srgrimes unlink(fname); 8191590Srgrimes mailing = NO; 8201590Srgrimes } 8211590Srgrimes ask(prompt); 8221590Srgrimes } 8231590Srgrimes} 8241590Srgrimes 825140389Sdelphijstatic void 826102944Sdwmalonegfrsub(FILE *infile) 8271590Srgrimes{ 8281590Srgrimes off_t frompos; 82937534Sghelmer int count; 8301590Srgrimes 8311590Srgrimes seensubj = seenfrom = NO; 8321590Srgrimes local = YES; 833126838Sbde subj[0] = from[0] = date[0] = '\0'; 8341590Srgrimes 8351590Srgrimes /* 8361590Srgrimes * Is this a normal message? 8371590Srgrimes */ 8381590Srgrimes if (fgets(inbuf, sizeof inbuf, infile)) { 8391590Srgrimes if (strncmp(inbuf, "From", 4)==0) { 8401590Srgrimes /* 8411590Srgrimes * expected form starts with From 8421590Srgrimes */ 8431590Srgrimes seenfrom = YES; 84482846Sache frompos = ftello(infile); 8451590Srgrimes ptr = from; 8461590Srgrimes in = nxtfld(inbuf); 84737534Sghelmer if (*in) { 84837534Sghelmer count = sizeof(from) - 1; 84937534Sghelmer while (*in && *in > ' ' && count-- > 0) { 85037534Sghelmer if (*in == ':' || *in == '@' || 85137534Sghelmer *in == '!') 85237534Sghelmer local = NO; 85337534Sghelmer *ptr++ = *in++; 85437534Sghelmer } 8551590Srgrimes } 856126838Sbde *ptr = '\0'; 8571590Srgrimes if (*(in = nxtfld(in))) 858300266Struckman strlcpy(date, in, sizeof date); 8591590Srgrimes else { 8601590Srgrimes date[0] = '\n'; 861126838Sbde date[1] = '\0'; 8621590Srgrimes } 8631590Srgrimes } 8641590Srgrimes else { 8651590Srgrimes /* 8661590Srgrimes * not the expected form 8671590Srgrimes */ 86882846Sache rewind(infile); 8691590Srgrimes return; 8701590Srgrimes } 8711590Srgrimes } 8721590Srgrimes else 8731590Srgrimes /* 8741590Srgrimes * empty file ? 8751590Srgrimes */ 8761590Srgrimes return; 8771590Srgrimes 8781590Srgrimes /* 8791590Srgrimes * look for Subject line until EOF or a blank line 8801590Srgrimes */ 8811590Srgrimes while (fgets(inbuf, sizeof inbuf, infile) 8821590Srgrimes && !(blankline = (inbuf[0] == '\n'))) { 8831590Srgrimes /* 8841590Srgrimes * extract Subject line 8851590Srgrimes */ 8861590Srgrimes if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { 8871590Srgrimes seensubj = YES; 88882846Sache frompos = ftello(infile); 889300266Struckman strlcpy(subj, nxtfld(inbuf), sizeof subj); 8901590Srgrimes } 8911590Srgrimes } 8921590Srgrimes if (!blankline) 8931590Srgrimes /* 8941590Srgrimes * ran into EOF 8951590Srgrimes */ 89682846Sache fseeko(infile, frompos, SEEK_SET); 8971590Srgrimes 8981590Srgrimes if (!seensubj) 8991590Srgrimes /* 9001590Srgrimes * for possible use with Mail 9011590Srgrimes */ 902300266Struckman strlcpy(subj, "(No Subject)\n", sizeof subj); 9031590Srgrimes} 9041590Srgrimes 905140389Sdelphijstatic char * 906140389Sdelphijnxtfld(char *s) 9071590Srgrimes{ 90812809Sache if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */ 90912809Sache if (*s) while (*s && isspace(*s)) s++; /* find start of next field */ 9101590Srgrimes return (s); 9111590Srgrimes} 912