msgs.c revision 256281
117680Spst/*- 217680Spst * Copyright (c) 1980, 1993 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that the following conditions 717680Spst * are met: 817680Spst * 1. Redistributions of source code must retain the above copyright 917680Spst * notice, this list of conditions and the following disclaimer. 1017680Spst * 2. Redistributions in binary form must reproduce the above copyright 1117680Spst * notice, this list of conditions and the following disclaimer in the 1217680Spst * documentation and/or other materials provided with the distribution. 1317680Spst * 4. Neither the name of the University nor the names of its contributors 1417680Spst * may be used to endorse or promote products derived from this software 1517680Spst * without specific prior written permission. 1617680Spst * 1717680Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1817680Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1917680Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2057278Sfenner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2157278Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2217680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2317680Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2417680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25127675Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26172686Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2717680Spst * SUCH DAMAGE. 2817680Spst */ 2956893Sfenner 3056893Sfenner#ifndef lint 3156893Sfennerstatic const char copyright[] = 3256893Sfenner"@(#) Copyright (c) 1980, 1993\n\ 33127675Sbms The Regents of the University of California. All rights reserved.\n"; 34146778Ssam#endif /* not lint */ 3517680Spst 36146778Ssam#if 0 37146778Ssam#ifndef lint 38146778Ssamstatic char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95"; 39146778Ssam#endif /* not lint */ 40146778Ssam#endif 41146778Ssam 42146778Ssam#include <sys/cdefs.h> 43146778Ssam__FBSDID("$FreeBSD: stable/10/usr.bin/msgs/msgs.c 241848 2012-10-22 03:07:05Z eadler $"); 44146778Ssam 45146778Ssam/* 46146778Ssam * msgs - a user bulletin board program 47146778Ssam * 48146778Ssam * usage: 49146778Ssam * msgs [fhlopq] [[-]number] to read messages 50146778Ssam * msgs -s to place messages 51146778Ssam * msgs -c [-days] to clean up the bulletin board 52146778Ssam * 53146778Ssam * prompt commands are: 54146778Ssam * y print message 55146778Ssam * n flush message, go to next message 56146778Ssam * q flush message, quit 57146778Ssam * p print message, turn on 'pipe thru more' mode 58146778Ssam * P print message, turn off 'pipe thru more' mode 59146778Ssam * - reprint last message 60146778Ssam * s[-][<num>] [<filename>] save message 61146778Ssam * m[-][<num>] mail with message in temp mbox 62146778Ssam * x exit without flushing this message 63146778Ssam * <num> print message number <num> 64146778Ssam */ 65146778Ssam 66146778Ssam#define V7 /* will look for TERM in the environment */ 67146778Ssam#define OBJECT /* will object to messages without Subjects */ 68146778Ssam/* #define REJECT */ /* will reject messages without Subjects 69146778Ssam (OBJECT must be defined also) */ 70146778Ssam/* #define UNBUFFERED *//* use unbuffered output */ 71146778Ssam 72146778Ssam#include <sys/param.h> 73146778Ssam#include <sys/stat.h> 74146778Ssam#include <ctype.h> 75146778Ssam#include <dirent.h> 76146778Ssam#include <err.h> 77146778Ssam#include <errno.h> 78146778Ssam#include <fcntl.h> 79146778Ssam#include <locale.h> 80146778Ssam#include <pwd.h> 81146778Ssam#include <setjmp.h> 82146778Ssam#include <termcap.h> 83146778Ssam#include <termios.h> 84172686Smlaier#include <signal.h> 85172686Smlaier#include <stdio.h> 86172686Smlaier#include <stdlib.h> 87146778Ssam#include <string.h> 88172686Smlaier#include <time.h> 89172686Smlaier#include <unistd.h> 90172686Smlaier#include "pathnames.h" 91172686Smlaier 92172686Smlaier#define CMODE 0644 /* bounds file creation mode */ 93172686Smlaier#define NO 0 9456893Sfenner#define YES 1 9556893Sfenner#define SUPERUSER 0 /* superuser uid */ 9656893Sfenner#define DAEMON 1 /* daemon uid */ 9756893Sfenner#define NLINES 24 /* default number of lines/crt screen */ 9856893Sfenner#define NDAYS 21 /* default keep time for messages */ 9956893Sfenner#define DAYS *24*60*60 /* seconds/day */ 10056893Sfenner#define MSGSRC ".msgsrc" /* user's rc file */ 10157278Sfenner#define BOUNDS "bounds" /* message bounds file */ 10257278Sfenner#define NEXT "Next message? [yq]" 10356893Sfenner#define MORE "More? [ynq]" 10456893Sfenner#define NOMORE "(No more) [q] ?" 10556893Sfenner 10656893Sfennertypedef char bool; 10757278Sfenner 10857278Sfennerstatic FILE *msgsrc; 10956893Sfennerstatic FILE *newmsg; 11056893Sfennerstatic const char *sep = "-"; 11156893Sfennerstatic char inbuf[BUFSIZ]; 11256893Sfennerstatic char fname[MAXPATHLEN]; 11356893Sfennerstatic char cmdbuf[MAXPATHLEN + MAXPATHLEN]; 11417680Spststatic char subj[128]; 11517680Spststatic char from[128]; 11617680Spststatic char date[128]; 11717680Spststatic char *ptr; 11817680Spststatic char *in; 11956893Sfennerstatic bool local; 12017680Spststatic bool ruptible; 12175118Sfennerstatic bool totty; 12275118Sfennerstatic bool seenfrom; 12356893Sfennerstatic bool seensubj; 12456893Sfennerstatic bool blankline; 12556893Sfennerstatic bool printing = NO; 12656893Sfennerstatic bool mailing = NO; 12756893Sfennerstatic bool quitit = NO; 12898527Sfennerstatic bool sending = NO; 12998527Sfennerstatic bool intrpflg = NO; 13056893Sfennerstatic uid_t uid; 13198527Sfennerstatic int msg; 13298527Sfennerstatic int prevmsg; 13398527Sfennerstatic int lct; 13498527Sfennerstatic int nlines; 13556893Sfennerstatic int Lpp = 0; 13698527Sfennerstatic time_t t; 13798527Sfennerstatic time_t keep; 13898527Sfenner 13998527Sfenner/* option initialization */ 14098527Sfennerstatic bool hdrs = NO; 14198527Sfennerstatic bool qopt = NO; 14298527Sfennerstatic bool hush = NO; 14398527Sfennerstatic bool send_msg = NO; 14498527Sfennerstatic bool locomode = NO; 14598527Sfennerstatic bool use_pager = NO; 14698527Sfennerstatic bool clean = NO; 14798527Sfennerstatic bool lastcmd = NO; 14856893Sfennerstatic jmp_buf tstpbuf; 14956893Sfenner 15056893Sfennerstatic void ask(const char *); 15198527Sfennerstatic void gfrsub(FILE *); 15298527Sfennerstatic int linecnt(FILE *); 15356893Sfennerstatic int next(char *); 154162021Ssamstatic char *nxtfld(char *); 15598527Sfennerstatic void onsusp(int); 15698527Sfennerstatic void onintr(int); 15798527Sfennerstatic void prmesg(int); 15898527Sfennerstatic void usage(void); 15998527Sfenner 16098527Sfennerint 16198527Sfennermain(int argc, char *argv[]) 16298527Sfenner{ 16398527Sfenner bool newrc, already; 16498527Sfenner int rcfirst = 0; /* first message to print (from .rc) */ 16598527Sfenner int rcback = 0; /* amount to back off of rcfirst */ 16698527Sfenner int firstmsg = 0, nextmsg = 0, lastmsg = 0; 16756893Sfenner int blast = 0; 16898527Sfenner struct stat buf; /* stat to check access of bounds */ 16998527Sfenner FILE *bounds; 17098527Sfenner char *cp; 17198527Sfenner 17298527Sfenner#ifdef UNBUFFERED 17398527Sfenner setbuf(stdout, NULL); 17498527Sfenner#endif 175147904Ssam setlocale(LC_ALL, ""); 176147904Ssam 177147904Ssam time(&t); 178147904Ssam if (setuid(uid = getuid()) != 0) 179162021Ssam err(1, "setuid failed"); 18098527Sfenner ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); 181162021Ssam if (ruptible) 18298527Sfenner signal(SIGINT, SIG_DFL); 18398527Sfenner 18498527Sfenner argc--, argv++; 18598527Sfenner while (argc > 0) { 18698527Sfenner if (isdigit(argv[0][0])) { /* starting message # */ 18798527Sfenner rcfirst = atoi(argv[0]); 18898527Sfenner } 18998527Sfenner else if (isdigit(argv[0][1])) { /* backward offset */ 19098527Sfenner rcback = atoi( &( argv[0][1] ) ); 191127675Sbms } 19298527Sfenner else { 19398527Sfenner ptr = *argv; 19498527Sfenner while (*ptr) switch (*ptr++) { 19598527Sfenner 19698527Sfenner case '-': 19798527Sfenner break; 19898527Sfenner 19956893Sfenner case 'c': 20056893Sfenner if (uid != SUPERUSER && uid != DAEMON) 20156893Sfenner errx(1, 20298527Sfenner "only the super-user can use the c flag"); 20398527Sfenner clean = YES; 20498527Sfenner break; 20598527Sfenner 20656893Sfenner case 'f': /* silently */ 20798527Sfenner hush = YES; 20856893Sfenner break; 20998527Sfenner 21098527Sfenner case 'h': /* headers only */ 21156893Sfenner hdrs = YES; 21256893Sfenner break; 21317680Spst 21456893Sfenner case 'l': /* local msgs only */ 21517680Spst locomode = YES; 21698527Sfenner break; 21798527Sfenner 21817680Spst case 'o': /* option to save last message */ 21998527Sfenner lastcmd = YES; 22098527Sfenner break; 22198527Sfenner 22217680Spst case 'p': /* pipe thru 'more' during long msgs */ 223127675Sbms use_pager = YES; 22498527Sfenner break; 22517680Spst 22698527Sfenner case 'q': /* query only */ 22798527Sfenner qopt = YES; 22898527Sfenner break; 22998527Sfenner 23098527Sfenner case 's': /* sending TO msgs */ 23198527Sfenner send_msg = YES; 23298527Sfenner break; 23356893Sfenner 23498527Sfenner default: 23598527Sfenner usage(); 23656893Sfenner } 23798527Sfenner } 23898527Sfenner argc--, argv++; 23956893Sfenner } 24098527Sfenner 24198527Sfenner /* 24256893Sfenner * determine current message bounds 24398527Sfenner */ 24456893Sfenner snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS); 24598527Sfenner 24698527Sfenner /* 24798527Sfenner * Test access rights to the bounds file 24898527Sfenner * This can be a little tricky. if(send_msg), then 24998527Sfenner * we will create it. We assume that if(send_msg), 25098527Sfenner * then you have write permission there. 25198527Sfenner * Else, it better be there, or we bail. 25217680Spst */ 25398527Sfenner if (send_msg != YES) { 25498527Sfenner if (stat(fname, &buf) < 0) { 25598527Sfenner if (hush != YES) { 25698527Sfenner err(errno, "%s", fname); 25798527Sfenner } else { 25898527Sfenner exit(1); 25998527Sfenner } 26098527Sfenner } 261162021Ssam } 26298527Sfenner bounds = fopen(fname, "r"); 26398527Sfenner 26498527Sfenner if (bounds != NULL) { 26598527Sfenner fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); 26698527Sfenner fclose(bounds); 26798527Sfenner blast = lastmsg; /* save upper bound */ 26898527Sfenner } 26998527Sfenner 27098527Sfenner if (clean) 27198527Sfenner keep = t - (rcback? rcback : NDAYS) DAYS; 27298527Sfenner 27398527Sfenner if (clean || bounds == NULL) { /* relocate message bounds */ 27498527Sfenner struct dirent *dp; 27556893Sfenner struct stat stbuf; 27698527Sfenner bool seenany = NO; 27798527Sfenner DIR *dirp; 27898527Sfenner 27998527Sfenner dirp = opendir(_PATH_MSGS); 28098527Sfenner if (dirp == NULL) 28198527Sfenner err(errno, "%s", _PATH_MSGS); 28298527Sfenner 28398527Sfenner firstmsg = 32767; 284162021Ssam lastmsg = 0; 28598527Sfenner 28698527Sfenner for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ 28756893Sfenner cp = dp->d_name; 28856893Sfenner int i = 0; 28998527Sfenner 29098527Sfenner if (dp->d_ino == 0) 29198527Sfenner continue; 29256893Sfenner if (dp->d_namlen == 0) 29356893Sfenner continue; 29498527Sfenner 29598527Sfenner if (clean) 29698527Sfenner snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp); 29798527Sfenner 29898527Sfenner while (isdigit(*cp)) 29998527Sfenner i = i * 10 + *cp++ - '0'; 30098527Sfenner if (*cp) 30198527Sfenner continue; /* not a message! */ 30298527Sfenner 30398527Sfenner if (clean) { 30498527Sfenner if (stat(inbuf, &stbuf) != 0) 30598527Sfenner continue; 30698527Sfenner if (stbuf.st_mtime < keep 30798527Sfenner && stbuf.st_mode&S_IWRITE) { 30898527Sfenner unlink(inbuf); 30998527Sfenner continue; 31098527Sfenner } 31156893Sfenner } 31298527Sfenner 31398527Sfenner if (i > lastmsg) 31498527Sfenner lastmsg = i; 31517680Spst if (i < firstmsg) 31656893Sfenner firstmsg = i; 31798527Sfenner seenany = YES; 31898527Sfenner } 31917680Spst closedir(dirp); 32056893Sfenner 32156893Sfenner if (!seenany) { 32256893Sfenner if (blast != 0) /* never lower the upper bound! */ 32398527Sfenner lastmsg = blast; 32498527Sfenner firstmsg = lastmsg + 1; 32598527Sfenner } 32656893Sfenner else if (blast > lastmsg) 32756893Sfenner lastmsg = blast; 32856893Sfenner 32956893Sfenner if (!send_msg) { 33098527Sfenner bounds = fopen(fname, "w"); 33198527Sfenner if (bounds == NULL) 33298527Sfenner err(errno, "%s", fname); 33356893Sfenner chmod(fname, CMODE); 33498527Sfenner fprintf(bounds, "%d %d\n", firstmsg, lastmsg); 33598527Sfenner fclose(bounds); 33698527Sfenner } 33798527Sfenner } 33898527Sfenner 33998527Sfenner if (send_msg) { 34098527Sfenner /* 34198527Sfenner * Send mode - place msgs in _PATH_MSGS 34298527Sfenner */ 34398527Sfenner bounds = fopen(fname, "w"); 34498527Sfenner if (bounds == NULL) 34598527Sfenner err(errno, "%s", fname); 34698527Sfenner 34798527Sfenner nextmsg = lastmsg + 1; 34856893Sfenner snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg); 34998527Sfenner newmsg = fopen(fname, "w"); 35098527Sfenner if (newmsg == NULL) 35156893Sfenner err(errno, "%s", fname); 35298527Sfenner chmod(fname, CMODE); 35398527Sfenner 35498527Sfenner fprintf(bounds, "%d %d\n", firstmsg, nextmsg); 35598527Sfenner fclose(bounds); 35698527Sfenner 35798527Sfenner sending = YES; 35898527Sfenner if (ruptible) 35956893Sfenner signal(SIGINT, onintr); 36098527Sfenner 36156893Sfenner if (isatty(fileno(stdin))) { 36298527Sfenner ptr = getpwuid(uid)->pw_name; 36356893Sfenner printf("Message %d:\nFrom %s %sSubject: ", 36498527Sfenner nextmsg, ptr, ctime(&t)); 36556893Sfenner fflush(stdout); 36698527Sfenner fgets(inbuf, sizeof inbuf, stdin); 36798527Sfenner putchar('\n'); 36898527Sfenner fflush(stdout); 36998527Sfenner fprintf(newmsg, "From %s %sSubject: %s\n", 37098527Sfenner ptr, ctime(&t), inbuf); 37198527Sfenner blankline = seensubj = YES; 37298527Sfenner } 37398527Sfenner else 37498527Sfenner blankline = seensubj = NO; 37598527Sfenner for (;;) { 37698527Sfenner fgets(inbuf, sizeof inbuf, stdin); 37798527Sfenner if (feof(stdin) || ferror(stdin)) 37898527Sfenner break; 37998527Sfenner blankline = (blankline || (inbuf[0] == '\n')); 38056893Sfenner seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); 38198527Sfenner fputs(inbuf, newmsg); 38298527Sfenner } 38398527Sfenner#ifdef OBJECT 38498527Sfenner if (!seensubj) { 38598527Sfenner printf("NOTICE: Messages should have a Subject field!\n"); 38698527Sfenner#ifdef REJECT 38798527Sfenner unlink(fname); 38898527Sfenner#endif 38998527Sfenner exit(1); 39098527Sfenner } 39198527Sfenner#endif 39298527Sfenner exit(ferror(stdin)); 39398527Sfenner } 39498527Sfenner if (clean) 39598527Sfenner exit(0); 39698527Sfenner 39798527Sfenner /* 39898527Sfenner * prepare to display messages 39998527Sfenner */ 40098527Sfenner totty = (isatty(fileno(stdout)) != 0); 40198527Sfenner use_pager = use_pager && totty; 40298527Sfenner 40398527Sfenner if ((cp = getenv("HOME")) == NULL || *cp == '\0') { 40498527Sfenner fprintf(stderr, "Error, no home directory!\n"); 40598527Sfenner exit(1); 40698527Sfenner } 40798527Sfenner snprintf(fname, sizeof(fname), "%s/%s", cp, MSGSRC); 40898527Sfenner msgsrc = fopen(fname, "r"); 40956893Sfenner if (msgsrc) { 41098527Sfenner newrc = NO; 41156893Sfenner fscanf(msgsrc, "%d\n", &nextmsg); 41256893Sfenner fclose(msgsrc); 41398527Sfenner if (nextmsg > lastmsg+1) { 41498527Sfenner printf("Warning: bounds have been reset (%d, %d)\n", 41556893Sfenner firstmsg, lastmsg); 41656893Sfenner truncate(fname, (off_t)0); 41756893Sfenner newrc = YES; 41856893Sfenner } 41956893Sfenner else if (!rcfirst) 42056893Sfenner rcfirst = nextmsg - rcback; 42156893Sfenner } 42256893Sfenner else 42356893Sfenner newrc = YES; 42456893Sfenner msgsrc = fopen(fname, "r+"); 42556893Sfenner if (msgsrc == NULL) 42656893Sfenner msgsrc = fopen(fname, "w"); 42756893Sfenner if (msgsrc == NULL) 42856893Sfenner err(errno, "%s", fname); 42956893Sfenner if (rcfirst) { 43075118Sfenner if (rcfirst > lastmsg+1) { 431146778Ssam printf("Warning: the last message is number %d.\n", 432146778Ssam lastmsg); 433172686Smlaier rcfirst = nextmsg; 434146778Ssam } 435146778Ssam if (rcfirst > firstmsg) 436146778Ssam firstmsg = rcfirst; /* don't set below first msg */ 437146778Ssam } 438146778Ssam if (newrc) { 439172686Smlaier nextmsg = firstmsg; 440146778Ssam rewind(msgsrc); 441146778Ssam fprintf(msgsrc, "%d\n", nextmsg); 442146778Ssam fflush(msgsrc); 443146778Ssam } 444146778Ssam 445146778Ssam#ifdef V7 44698527Sfenner if (totty) { 447172686Smlaier struct winsize win; 448146778Ssam if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) 449146778Ssam Lpp = win.ws_row; 45056893Sfenner if (Lpp <= 0) { 45156893Sfenner if (tgetent(inbuf, getenv("TERM")) <= 0 45256893Sfenner || (Lpp = tgetnum("li")) <= 0) { 45356893Sfenner Lpp = NLINES; 45456893Sfenner } 45556893Sfenner } 45656893Sfenner } 45756893Sfenner#endif 45856893Sfenner Lpp -= 6; /* for headers, etc. */ 45956893Sfenner 46056893Sfenner already = NO; 46156893Sfenner prevmsg = firstmsg; 46256893Sfenner printing = YES; 46356893Sfenner if (ruptible) 46456893Sfenner signal(SIGINT, onintr); 46556893Sfenner 46656893Sfenner /* 46756893Sfenner * Main program loop 46856893Sfenner */ 46956893Sfenner for (msg = firstmsg; msg <= lastmsg; msg++) { 47056893Sfenner 47156893Sfenner snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg); 47256893Sfenner newmsg = fopen(fname, "r"); 47356893Sfenner if (newmsg == NULL) 47456893Sfenner continue; 47556893Sfenner 47656893Sfenner gfrsub(newmsg); /* get From and Subject fields */ 47756893Sfenner if (locomode && !local) { 47856893Sfenner fclose(newmsg); 47956893Sfenner continue; 48056893Sfenner } 48156893Sfenner 48256893Sfenner if (qopt) { /* This has to be located here */ 48356893Sfenner printf("There are new messages.\n"); 48456893Sfenner exit(0); 48556893Sfenner } 48656893Sfenner 48756893Sfenner if (already && !hdrs) 48856893Sfenner putchar('\n'); 48956893Sfenner 49056893Sfenner /* 49156893Sfenner * Print header 49256893Sfenner */ 49356893Sfenner if (totty) 49456893Sfenner signal(SIGTSTP, onsusp); 49556893Sfenner (void) setjmp(tstpbuf); 49656893Sfenner already = YES; 49756893Sfenner nlines = 2; 49856893Sfenner if (seenfrom) { 49956893Sfenner printf("Message %d:\nFrom %s %s", msg, from, date); 50056893Sfenner nlines++; 50156893Sfenner } 50256893Sfenner if (seensubj) { 50356893Sfenner printf("Subject: %s", subj); 50456893Sfenner nlines++; 50556893Sfenner } 50656893Sfenner else { 50756893Sfenner if (seenfrom) { 50856893Sfenner putchar('\n'); 50956893Sfenner nlines++; 51056893Sfenner } 51156893Sfenner while (nlines < 6 51256893Sfenner && fgets(inbuf, sizeof inbuf, newmsg) 51356893Sfenner && inbuf[0] != '\n') { 51456893Sfenner fputs(inbuf, stdout); 51556893Sfenner nlines++; 51656893Sfenner } 51756893Sfenner } 51856893Sfenner 51956893Sfenner lct = linecnt(newmsg); 52056893Sfenner if (lct) 52156893Sfenner printf("(%d%sline%s) ", lct, seensubj? " " : " more ", 52256893Sfenner (lct == 1) ? "" : "s"); 52356893Sfenner 52456893Sfenner if (hdrs) { 52556893Sfenner printf("\n-----\n"); 52656893Sfenner fclose(newmsg); 52756893Sfenner continue; 52856893Sfenner } 52956893Sfenner 53056893Sfenner /* 53156893Sfenner * Ask user for command 53298527Sfenner */ 53356893Sfenner if (totty) 534162021Ssam ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); 53556893Sfenner else 53656893Sfenner inbuf[0] = 'y'; 53798527Sfenner if (totty) 53856893Sfenner signal(SIGTSTP, SIG_DFL); 539162021Ssamcmnd: 54056893Sfenner in = inbuf; 54156893Sfenner switch (*in) { 54298527Sfenner case 'x': 54356893Sfenner /* FALLTHROUGH */ 54456893Sfenner case 'X': 54556893Sfenner exit(0); 54656893Sfenner /* NOTREACHED */ 54756893Sfenner 54856893Sfenner case 'q': 54956893Sfenner /* FALLTHROUGH */ 550162021Ssam case 'Q': 55156893Sfenner quitit = YES; 55256893Sfenner printf("--Postponed--\n"); 55356893Sfenner exit(0); 554162021Ssam /* NOTREACHED */ 55556893Sfenner 55656893Sfenner case 'n': 55756893Sfenner /* FALLTHROUGH */ 55898527Sfenner case 'N': 55956893Sfenner if (msg >= nextmsg) sep = "Flushed"; 56056893Sfenner prevmsg = msg; 56156893Sfenner break; 56256893Sfenner 56356893Sfenner case 'p': 56456893Sfenner /* FALLTHROUGH */ 56556893Sfenner case 'P': 56656893Sfenner use_pager = (*in++ == 'p'); 56756893Sfenner /* FALLTHROUGH */ 56898527Sfenner case '\n': 56956893Sfenner /* FALLTHROUGH */ 57056893Sfenner case 'y': 57156893Sfenner default: 57256893Sfenner if (*in == '-') { 57356893Sfenner msg = prevmsg-1; 57456893Sfenner sep = "replay"; 57556893Sfenner break; 57656893Sfenner } 57756893Sfenner if (isdigit(*in)) { 57856893Sfenner msg = next(in); 57956893Sfenner sep = in; 58056893Sfenner break; 58198527Sfenner } 58298527Sfenner 58356893Sfenner prmesg(nlines + lct + (seensubj? 1 : 0)); 58456893Sfenner prevmsg = msg; 58556893Sfenner 58656893Sfenner } 58756893Sfenner 58856893Sfenner printf("--%s--\n", sep); 58956893Sfenner sep = "-"; 59056893Sfenner if (msg >= nextmsg) { 59156893Sfenner nextmsg = msg + 1; 59256893Sfenner rewind(msgsrc); 59356893Sfenner fprintf(msgsrc, "%d\n", nextmsg); 59456893Sfenner fflush(msgsrc); 59556893Sfenner } 59656893Sfenner if (newmsg) 59756893Sfenner fclose(newmsg); 59856893Sfenner if (quitit) 59956893Sfenner break; 60056893Sfenner } 60156893Sfenner 60256893Sfenner /* 60356893Sfenner * Make sure .rc file gets updated 60456893Sfenner */ 60556893Sfenner if (--msg >= nextmsg) { 60656893Sfenner nextmsg = msg + 1; 60756893Sfenner rewind(msgsrc); 60856893Sfenner fprintf(msgsrc, "%d\n", nextmsg); 60956893Sfenner fflush(msgsrc); 61056893Sfenner } 61156893Sfenner if (already && !quitit && lastcmd && totty) { 61256893Sfenner /* 61356893Sfenner * save or reply to last message? 61456893Sfenner */ 61556893Sfenner msg = prevmsg; 61656893Sfenner ask(NOMORE); 61756893Sfenner if (inbuf[0] == '-' || isdigit(inbuf[0])) 61856893Sfenner goto cmnd; 61956893Sfenner } 62056893Sfenner if (!(already || hush || qopt)) 62156893Sfenner printf("No new messages.\n"); 62256893Sfenner exit(0); 62356893Sfenner /* NOTREACHED */ 62456893Sfenner} 62556893Sfenner 62656893Sfennerstatic void 62756893Sfennerusage(void) 62856893Sfenner{ 62956893Sfenner fprintf(stderr, "usage: msgs [fhlopq] [[-]number]\n"); 63056893Sfenner exit(1); 63156893Sfenner} 63257278Sfenner 63357278Sfennerstatic void 63456893Sfennerprmesg(int length) 63556893Sfenner{ 63656893Sfenner FILE *outf; 637146778Ssam char *env_pager; 63856893Sfenner 639172686Smlaier if (use_pager && length > Lpp) { 640172686Smlaier signal(SIGPIPE, SIG_IGN); 641172686Smlaier signal(SIGQUIT, SIG_IGN); 642172686Smlaier if ((env_pager = getenv("PAGER")) == NULL) { 643172686Smlaier snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp); 644172686Smlaier } else { 645172686Smlaier snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager); 646172686Smlaier } 647172686Smlaier outf = popen(cmdbuf, "w"); 64856893Sfenner if (!outf) 649146778Ssam outf = stdout; 65056893Sfenner else 65156893Sfenner setbuf(outf, (char *)NULL); 65256893Sfenner } 65356893Sfenner else 65456893Sfenner outf = stdout; 65556893Sfenner 65656893Sfenner if (seensubj) 65756893Sfenner putc('\n', outf); 658146778Ssam 659172686Smlaier while (fgets(inbuf, sizeof inbuf, newmsg)) { 660146778Ssam fputs(inbuf, outf); 661146778Ssam if (ferror(outf)) { 662146778Ssam clearerr(outf); 663146778Ssam break; 664146778Ssam } 66556893Sfenner } 666146778Ssam 667146778Ssam if (outf != stdout) { 668146778Ssam pclose(outf); 66956893Sfenner signal(SIGPIPE, SIG_DFL); 670146778Ssam signal(SIGQUIT, SIG_DFL); 671127675Sbms } 672146778Ssam else { 673127675Sbms fflush(stdout); 674127675Sbms } 675127675Sbms 676146778Ssam /* force wait on output */ 677146778Ssam tcdrain(fileno(stdout)); 678127675Sbms} 679127675Sbms 680146778Ssamstatic void 681127675Sbmsonintr(int unused __unused) 682127675Sbms{ 683127675Sbms signal(SIGINT, onintr); 684127675Sbms if (mailing) 685146778Ssam unlink(fname); 686146778Ssam if (sending) { 687146778Ssam unlink(fname); 688146778Ssam puts("--Killed--"); 689146778Ssam exit(1); 690146778Ssam } 691146778Ssam if (printing) { 692146778Ssam putchar('\n'); 693146778Ssam if (hdrs) 694146778Ssam exit(0); 695146778Ssam sep = "Interrupt"; 696146778Ssam if (newmsg) 697146778Ssam fseeko(newmsg, (off_t)0, SEEK_END); 698146778Ssam intrpflg = YES; 699111729Sfenner } 700146778Ssam} 701146778Ssam 70256893Sfenner/* 70356893Sfenner * We have just gotten a susp. Suspend and prepare to resume. 704146778Ssam */ 705146778Ssamstatic void 706146778Ssamonsusp(int unused __unused) 707146778Ssam{ 708146778Ssam signal(SIGTSTP, SIG_DFL); 70956893Sfenner sigsetmask(0); 710146778Ssam kill(0, SIGTSTP); 711146778Ssam signal(SIGTSTP, onsusp); 71298527Sfenner if (!mailing) 71356893Sfenner longjmp(tstpbuf, 0); 71456893Sfenner} 715146778Ssam 71698527Sfennerstatic int 71798527Sfennerlinecnt(FILE *f) 718146778Ssam{ 719146778Ssam off_t oldpos = ftello(f); 720127675Sbms int l = 0; 721146778Ssam char lbuf[BUFSIZ]; 722146778Ssam 723127675Sbms while (fgets(lbuf, sizeof lbuf, f)) 724127675Sbms l++; 725146778Ssam clearerr(f); 726127675Sbms fseeko(f, oldpos, SEEK_SET); 727127675Sbms return (l); 728127675Sbms} 729127675Sbms 730127675Sbmsstatic int 731127675Sbmsnext(char *buf) 732127675Sbms{ 733127675Sbms int i; 734127675Sbms sscanf(buf, "%d", &i); 73556893Sfenner sprintf(buf, "Goto %d", i); 736146778Ssam return(--i); 737146778Ssam} 738146778Ssam 73956893Sfennerstatic void 740146778Ssamask(const char *prompt) 741146778Ssam{ 742146778Ssam char inch; 743146778Ssam int n, cmsg, fd; 74456893Sfenner off_t oldpos; 74556893Sfenner FILE *cpfrom, *cpto; 74656893Sfenner 74756893Sfenner printf("%s ", prompt); 748146778Ssam fflush(stdout); 74998527Sfenner intrpflg = NO; 75056893Sfenner (void) fgets(inbuf, sizeof inbuf, stdin); 75156893Sfenner if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') 752172686Smlaier inbuf[n - 1] = '\0'; 753172686Smlaier if (intrpflg) 754172686Smlaier inbuf[0] = 'x'; 755172686Smlaier 756172686Smlaier /* 757172686Smlaier * Handle 'mail' and 'save' here. 758172686Smlaier */ 759172686Smlaier if ((inch = inbuf[0]) == 's' || inch == 'm') { 76056893Sfenner if (inbuf[1] == '-') 76156893Sfenner cmsg = prevmsg; 76256893Sfenner else if (isdigit(inbuf[1])) 76375118Sfenner cmsg = atoi(&inbuf[1]); 764172686Smlaier else 765172686Smlaier cmsg = msg; 766172686Smlaier snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg); 767172686Smlaier 768172686Smlaier oldpos = ftello(newmsg); 769172686Smlaier 77098527Sfenner cpfrom = fopen(fname, "r"); 771146778Ssam if (!cpfrom) { 77256893Sfenner printf("Message %d not found\n", cmsg); 77356893Sfenner ask (prompt); 77498527Sfenner return; 77556893Sfenner } 77656893Sfenner 77756893Sfenner if (inch == 's') { 778172686Smlaier in = nxtfld(inbuf); 779172686Smlaier if (*in) { 780172686Smlaier for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ 78156893Sfenner fname[n] = in[n]; 78256893Sfenner } 78398527Sfenner fname[n] = '\0'; 78456893Sfenner } 785146778Ssam else 78656893Sfenner strcpy(fname, "Messages"); 78756893Sfenner fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND); 78856893Sfenner } 78956893Sfenner else { 79056893Sfenner strcpy(fname, _PATH_TMP); 79156893Sfenner fd = mkstemp(fname); 79256893Sfenner if (fd != -1) { 79356893Sfenner snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, 79456893Sfenner fname); 79556893Sfenner mailing = YES; 79656893Sfenner } 79756893Sfenner } 79856893Sfenner if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) { 79956893Sfenner if (fd != -1) 80056893Sfenner close(fd); 80156893Sfenner warn("%s", fname); 80256893Sfenner mailing = NO; 80356893Sfenner fseeko(newmsg, oldpos, SEEK_SET); 80456893Sfenner ask(prompt); 805146778Ssam return; 806146778Ssam } 807146778Ssam 808146778Ssam while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom))) 809146778Ssam fwrite(inbuf, 1, n, cpto); 810146778Ssam 811146778Ssam fclose(cpfrom); 812146778Ssam fclose(cpto); 813146778Ssam fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */ 814146778Ssam if (inch == 's') 815146778Ssam printf("Message %d saved in \"%s\"\n", cmsg, fname); 816146778Ssam else { 817146778Ssam system(cmdbuf); 818146778Ssam unlink(fname); 819146778Ssam mailing = NO; 820146778Ssam } 821146778Ssam ask(prompt); 822146778Ssam } 823146778Ssam} 824146778Ssam 825146778Ssamstatic void 826146778Ssamgfrsub(FILE *infile) 827146778Ssam{ 828146778Ssam off_t frompos; 829146778Ssam int count; 830146778Ssam 831146778Ssam seensubj = seenfrom = NO; 832146778Ssam local = YES; 833146778Ssam subj[0] = from[0] = date[0] = '\0'; 834146778Ssam 835146778Ssam /* 836146778Ssam * Is this a normal message? 837146778Ssam */ 838146778Ssam if (fgets(inbuf, sizeof inbuf, infile)) { 839146778Ssam if (strncmp(inbuf, "From", 4)==0) { 840146778Ssam /* 841146778Ssam * expected form starts with From 842146778Ssam */ 843146778Ssam seenfrom = YES; 844146778Ssam frompos = ftello(infile); 84556893Sfenner ptr = from; 84656893Sfenner in = nxtfld(inbuf); 84756893Sfenner if (*in) { 84856893Sfenner count = sizeof(from) - 1; 84956893Sfenner while (*in && *in > ' ' && count-- > 0) { 85056893Sfenner if (*in == ':' || *in == '@' || 85156893Sfenner *in == '!') 85256893Sfenner local = NO; 85356893Sfenner *ptr++ = *in++; 85456893Sfenner } 85556893Sfenner } 856146778Ssam *ptr = '\0'; 85756893Sfenner if (*(in = nxtfld(in))) 85856893Sfenner strncpy(date, in, sizeof date); 85956893Sfenner else { 86056893Sfenner date[0] = '\n'; 86156893Sfenner date[1] = '\0'; 86256893Sfenner } 86356893Sfenner } 86456893Sfenner else { 86556893Sfenner /* 86656893Sfenner * not the expected form 867146778Ssam */ 86856893Sfenner rewind(infile); 869146778Ssam return; 87056893Sfenner } 871146778Ssam } 87256893Sfenner else 87356893Sfenner /* 87456893Sfenner * empty file ? 87556893Sfenner */ 87656893Sfenner return; 87756893Sfenner 87856893Sfenner /* 879146778Ssam * look for Subject line until EOF or a blank line 88056893Sfenner */ 88156893Sfenner while (fgets(inbuf, sizeof inbuf, infile) 88256893Sfenner && !(blankline = (inbuf[0] == '\n'))) { 88356893Sfenner /* 88456893Sfenner * extract Subject line 88556893Sfenner */ 88656893Sfenner if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { 88756893Sfenner seensubj = YES; 88856893Sfenner frompos = ftello(infile); 88956893Sfenner strncpy(subj, nxtfld(inbuf), sizeof subj); 89056893Sfenner } 891146778Ssam } 89256893Sfenner if (!blankline) 89356893Sfenner /* 894146778Ssam * ran into EOF 89556893Sfenner */ 89656893Sfenner fseeko(infile, frompos, SEEK_SET); 89756893Sfenner 89856893Sfenner if (!seensubj) 89956893Sfenner /* 90056893Sfenner * for possible use with Mail 90156893Sfenner */ 902146778Ssam strncpy(subj, "(No Subject)\n", sizeof subj); 90356893Sfenner} 90456893Sfenner 90556893Sfennerstatic char * 90656893Sfennernxtfld(char *s) 90756893Sfenner{ 90856893Sfenner if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */ 90956893Sfenner if (*s) while (*s && isspace(*s)) s++; /* find start of next field */ 91056893Sfenner return (s); 91156893Sfenner} 91256893Sfenner